aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.checkpatch14
-rw-r--r--.clang-format130
-rw-r--r--.cppcheck22
-rw-r--r--.gitignore4
-rw-r--r--.readthedocs.yaml23
-rw-r--r--components/app/fwu-tool/app/fwu_app.cpp203
-rw-r--r--components/app/fwu-tool/app/fwu_app.h105
-rw-r--r--components/app/fwu-tool/app/metadata_reader.cpp86
-rw-r--r--components/app/fwu-tool/app/metadata_reader.h53
-rw-r--r--components/app/fwu-tool/app/metadata_v1_reader.cpp67
-rw-r--r--components/app/fwu-tool/app/metadata_v2_reader.cpp67
-rw-r--r--components/app/fwu-tool/cmd_print_image_dir.cpp57
-rw-r--r--components/app/fwu-tool/cmd_print_image_dir.h15
-rw-r--r--components/app/fwu-tool/cmd_print_metadata_v1.cpp63
-rw-r--r--components/app/fwu-tool/cmd_print_metadata_v1.h15
-rw-r--r--components/app/fwu-tool/cmd_print_metadata_v2.cpp85
-rw-r--r--components/app/fwu-tool/cmd_print_metadata_v2.h15
-rw-r--r--components/app/fwu-tool/cmd_update_image.cpp62
-rw-r--r--components/app/fwu-tool/cmd_update_image.h18
-rw-r--r--components/app/fwu-tool/component.cmake38
-rw-r--r--components/app/fwu-tool/fwu_main.cpp218
-rw-r--r--components/app/fwu-tool/print_uuid.cpp18
-rw-r--r--components/app/fwu-tool/print_uuid.h16
-rw-r--r--components/app/platform-inspect/attest_report_fetcher.cpp17
-rw-r--r--components/app/remote-test-runner/remote_test_runner.cpp29
-rw-r--r--components/app/ts-demo/test/ts-demo_tests.cpp29
-rw-r--r--components/app/ts-demo/ts-demo.cpp2
-rw-r--r--components/common/cbor_dump/cbor_dump.c8
-rw-r--r--components/common/crc32/component.cmake25
-rw-r--r--components/common/crc32/crc32.c117
-rw-r--r--components/common/crc32/crc32.h37
-rw-r--r--components/common/crc32/crc32_discovery.h22
-rw-r--r--components/common/crc32/crc32_linux.c17
-rw-r--r--components/common/crc32/crc32_sp.c22
-rw-r--r--components/common/crc32/test/component.cmake (renamed from components/service/discovery/client/component.cmake)4
-rw-r--r--components/common/crc32/test/crc32_test.cpp58
-rw-r--r--components/common/fdt/component.cmake15
-rw-r--r--components/common/fdt/fdt_helpers.c74
-rw-r--r--components/common/fdt/fdt_helpers.h12
-rw-r--r--components/common/libc/component.cmake13
-rw-r--r--components/common/libc/include/assert_fail_handler.h17
-rw-r--r--components/common/libc/include/libc_init.h15
-rw-r--r--components/common/trace/trace.c10
-rw-r--r--components/common/utils/component.cmake10
-rw-r--r--components/common/utils/include/compiler.h8
-rw-r--r--components/common/utils/include/util.h11
-rw-r--r--components/common/uuid/test/uuid_tests.cpp202
-rw-r--r--components/common/uuid/uuid.c166
-rw-r--r--components/common/uuid/uuid.h94
-rw-r--r--components/config/interface/config_store.h3
-rw-r--r--components/config/loader/sp/sp_config_loader.c355
-rw-r--r--components/config/loader/sp/sp_config_loader.h6
-rw-r--r--components/config/ramstore/config_ramstore.c16
-rw-r--r--components/config/ramstore/test/ramstore_tests.cpp4
-rw-r--r--components/media/disk/component.cmake19
-rw-r--r--components/media/disk/disk_images/component.cmake13
-rw-r--r--components/media/disk/disk_images/multi_location_fw.imgbin0 -> 98304 bytes
-rw-r--r--components/media/disk/disk_images/readme.rst75
-rw-r--r--components/media/disk/disk_images/ref_partition.c11416
-rw-r--r--components/media/disk/disk_images/ref_partition.h17
-rw-r--r--components/media/disk/disk_images/ref_partition.imgbin0 -> 136704 bytes
-rw-r--r--components/media/disk/disk_images/single_location_fw.imgbin0 -> 57344 bytes
-rw-r--r--components/media/disk/formatter/component.cmake13
-rw-r--r--components/media/disk/formatter/disk_formatter.c38
-rw-r--r--components/media/disk/formatter/disk_formatter.h37
-rw-r--r--components/media/disk/gpt_iterator/component.cmake13
-rw-r--r--components/media/disk/gpt_iterator/gpt_iterator.c128
-rw-r--r--components/media/disk/gpt_iterator/gpt_iterator.h100
-rw-r--r--components/media/disk/guid.h45
-rw-r--r--components/media/disk/partition_table.h26
-rw-r--r--components/media/disk/test/component.cmake14
-rw-r--r--components/media/disk/test/gpt_iterator_tests.cpp140
-rw-r--r--components/media/disk/test/partition_table_tests.cpp163
-rw-r--r--components/media/volume/base_io_dev/base_io_dev.h29
-rw-r--r--components/media/volume/base_io_dev/component.cmake17
-rw-r--r--components/media/volume/block_volume/block_volume.c321
-rw-r--r--components/media/volume/block_volume/block_volume.h74
-rw-r--r--components/media/volume/block_volume/component.cmake13
-rw-r--r--components/media/volume/block_volume/test/block_volume_tests.cpp321
-rw-r--r--components/media/volume/block_volume/test/component.cmake13
-rw-r--r--components/media/volume/component.cmake13
-rw-r--r--components/media/volume/factory/single_flash/component.cmake13
-rw-r--r--components/media/volume/factory/single_flash/volume_factory.c102
-rw-r--r--components/media/volume/factory/volume_factory.h68
-rw-r--r--components/media/volume/index/component.cmake13
-rw-r--r--components/media/volume/index/volume_index.c119
-rw-r--r--components/media/volume/index/volume_index.h89
-rw-r--r--components/media/volume/volume.c72
-rw-r--r--components/media/volume/volume.h162
-rw-r--r--components/messaging/ffa/libsp/component.cmake6
-rw-r--r--components/messaging/ffa/libsp/ffa.c207
-rw-r--r--components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c63
-rw-r--r--components/messaging/ffa/libsp/include/ffa_api.h112
-rw-r--r--components/messaging/ffa/libsp/include/ffa_api_defines.h76
-rw-r--r--components/messaging/ffa/libsp/include/ffa_api_types.h46
-rw-r--r--components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h18
-rw-r--r--components/messaging/ffa/libsp/include/sp_api.h4
-rw-r--r--components/messaging/ffa/libsp/include/sp_discovery.h15
-rw-r--r--components/messaging/ffa/libsp/include/sp_memory_management.h65
-rw-r--r--components/messaging/ffa/libsp/include/sp_messaging.h11
-rw-r--r--components/messaging/ffa/libsp/mock/component.cmake30
-rw-r--r--components/messaging/ffa/libsp/mock/mock_assert.cpp (renamed from components/messaging/ffa/libsp/test/mock_assert.cpp)0
-rw-r--r--components/messaging/ffa/libsp/mock/mock_assert.h (renamed from components/messaging/ffa/libsp/test/mock_assert.h)0
-rw-r--r--components/messaging/ffa/libsp/mock/mock_ffa_api.cpp (renamed from components/messaging/ffa/libsp/test/mock_ffa_api.cpp)176
-rw-r--r--components/messaging/ffa/libsp/mock/mock_ffa_api.h (renamed from components/messaging/ffa/libsp/test/mock_ffa_api.h)48
-rw-r--r--components/messaging/ffa/libsp/mock/mock_ffa_internal_api.cpp (renamed from components/messaging/ffa/libsp/test/mock_ffa_internal_api.cpp)0
-rw-r--r--components/messaging/ffa/libsp/mock/mock_ffa_internal_api.h (renamed from components/messaging/ffa/libsp/test/mock_ffa_internal_api.h)0
-rw-r--r--components/messaging/ffa/libsp/mock/mock_sp_discovery.cpp116
-rw-r--r--components/messaging/ffa/libsp/mock/mock_sp_discovery.h39
-rw-r--r--components/messaging/ffa/libsp/mock/mock_sp_memory_management.cpp523
-rw-r--r--components/messaging/ffa/libsp/mock/mock_sp_memory_management.h98
-rw-r--r--components/messaging/ffa/libsp/mock/mock_sp_messaging.cpp86
-rw-r--r--components/messaging/ffa/libsp/mock/mock_sp_messaging.h39
-rw-r--r--components/messaging/ffa/libsp/mock/mock_sp_rxtx.cpp (renamed from components/messaging/ffa/libsp/test/mock_sp_rxtx.cpp)0
-rw-r--r--components/messaging/ffa/libsp/mock/mock_sp_rxtx.h (renamed from components/messaging/ffa/libsp/test/mock_sp_rxtx.h)0
-rw-r--r--components/messaging/ffa/libsp/mock/test/test_mock_assert.cpp (renamed from components/messaging/ffa/libsp/test/test_mock_assert.cpp)0
-rw-r--r--components/messaging/ffa/libsp/mock/test/test_mock_ffa_api.cpp (renamed from components/messaging/ffa/libsp/test/test_mock_ffa_api.cpp)91
-rw-r--r--components/messaging/ffa/libsp/mock/test/test_mock_ffa_internal_api.cpp (renamed from components/messaging/ffa/libsp/test/test_mock_ffa_internal_api.cpp)0
-rw-r--r--components/messaging/ffa/libsp/mock/test/test_mock_sp_discovery.cpp117
-rw-r--r--components/messaging/ffa/libsp/mock/test/test_mock_sp_messaging.cpp79
-rw-r--r--components/messaging/ffa/libsp/mock/test/test_mock_sp_rxtx.cpp (renamed from components/messaging/ffa/libsp/test/test_mock_sp_rxtx.cpp)0
-rw-r--r--components/messaging/ffa/libsp/sp_discovery.c170
-rw-r--r--components/messaging/ffa/libsp/sp_memory_management.c114
-rw-r--r--components/messaging/ffa/libsp/sp_messaging.c93
-rw-r--r--components/messaging/ffa/libsp/sp_rxtx.c4
-rw-r--r--components/messaging/ffa/libsp/test/test_ffa_api.cpp585
-rw-r--r--components/messaging/ffa/libsp/test/test_mock_sp_memory_management.cpp260
-rw-r--r--components/messaging/ffa/libsp/test/test_sp_discovery.cpp74
-rw-r--r--components/messaging/ffa/libsp/test/test_sp_memory_management.cpp238
-rw-r--r--components/messaging/ffa/libsp/test/test_sp_messaging.cpp569
-rw-r--r--components/messaging/ffa/libsp/test/test_sp_rxtx.cpp14
-rw-r--r--components/messaging/ffa/libsp/tests.cmake91
-rw-r--r--components/messaging/openamp/sp/component.cmake24
-rw-r--r--components/messaging/openamp/sp/openamp_messenger.c166
-rw-r--r--components/messaging/openamp/sp/openamp_messenger.h33
-rw-r--r--components/messaging/openamp/sp/openamp_messenger_api.h36
-rw-r--r--components/messaging/openamp/sp/openamp_mhu.c191
-rw-r--r--components/messaging/openamp/sp/openamp_mhu.h19
-rw-r--r--components/messaging/openamp/sp/openamp_virtio.c552
-rw-r--r--components/messaging/openamp/sp/openamp_virtio.h24
-rw-r--r--components/rpc/common/caller/component.cmake10
-rw-r--r--components/rpc/common/caller/rpc_caller.c60
-rw-r--r--components/rpc/common/caller/rpc_caller.h86
-rw-r--r--components/rpc/common/caller/rpc_caller_session.c217
-rw-r--r--components/rpc/common/caller/rpc_caller_session.h152
-rw-r--r--components/rpc/common/demux/rpc_demux.c57
-rw-r--r--components/rpc/common/demux/rpc_demux.h78
-rw-r--r--components/rpc/common/endpoint/component.cmake (renamed from components/rpc/ffarpc/endpoint/component.cmake)2
-rw-r--r--components/rpc/common/endpoint/rpc_interface.h138
-rw-r--r--components/rpc/common/endpoint/rpc_service_interface.c16
-rw-r--r--components/rpc/common/endpoint/rpc_service_interface.h88
-rw-r--r--components/rpc/common/interface/component.cmake12
-rw-r--r--components/rpc/common/interface/rpc_caller.h94
-rw-r--r--components/rpc/common/interface/rpc_status.h30
-rw-r--r--components/rpc/common/interface/rpc_uuid.c13
-rw-r--r--components/rpc/common/interface/rpc_uuid.h40
-rw-r--r--components/rpc/common/logging/logging_caller.c2
-rw-r--r--components/rpc/common/test/call_param_buf_comparator.h50
-rw-r--r--components/rpc/common/test/call_req_comparator.h68
-rw-r--r--components/rpc/common/test/component.cmake18
-rw-r--r--components/rpc/common/test/mock_rpc_interface.cpp26
-rw-r--r--components/rpc/common/test/mock_rpc_interface.h9
-rw-r--r--components/rpc/common/test/rpc_buffer_comparator.h50
-rw-r--r--components/rpc/common/test/rpc_request_comparator.h68
-rw-r--r--components/rpc/common/test/test_mock_rpc_interface.cpp38
-rw-r--r--components/rpc/direct/direct_caller.c166
-rw-r--r--components/rpc/direct/direct_caller.h33
-rw-r--r--components/rpc/dummy/dummy_caller.c133
-rw-r--r--components/rpc/dummy/dummy_caller.h17
-rw-r--r--components/rpc/ffarpc/caller/linux/component.cmake19
-rw-r--r--components/rpc/ffarpc/caller/linux/ffarpc_caller.c399
-rw-r--r--components/rpc/ffarpc/caller/linux/ffarpc_caller.h50
-rw-r--r--components/rpc/ffarpc/caller/sp/ffarpc_caller.c298
-rw-r--r--components/rpc/ffarpc/caller/sp/ffarpc_caller.h40
-rw-r--r--components/rpc/ffarpc/caller/sp/ffarpc_sp_call_args.h44
-rw-r--r--components/rpc/ffarpc/endpoint/ffarpc_call_args.h50
-rw-r--r--components/rpc/ffarpc/endpoint/ffarpc_call_ep.c249
-rw-r--r--components/rpc/ffarpc/endpoint/ffarpc_call_ep.h41
-rw-r--r--components/rpc/ffarpc/endpoint/ffarpc_call_ops.h29
-rw-r--r--components/rpc/http/caller/component.cmake (renamed from components/rpc/ffarpc/caller/sp/component.cmake)4
-rw-r--r--components/rpc/http/caller/http_caller.c326
-rw-r--r--components/rpc/http/caller/http_caller.h50
-rw-r--r--components/rpc/http/caller/test/component.cmake13
-rw-r--r--components/rpc/http/caller/test/http_caller_tests.cpp104
-rw-r--r--components/rpc/mm_communicate/caller/linux/carveout.c17
-rw-r--r--components/rpc/mm_communicate/caller/linux/component.cmake10
-rw-r--r--components/rpc/mm_communicate/caller/linux/mm_communicate_caller.c577
-rw-r--r--components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h43
-rw-r--r--components/rpc/mm_communicate/common/mm_communicate_call_args.h15
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/component.cmake11
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c74
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h6
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/test/mm_service_call_req_comparator.h14
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.cpp12
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.h4
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/test/test_mm_communicate_call_ep.cpp146
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/test/test_mock_mm_service.cpp16
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/tests.cmake6
-rw-r--r--components/rpc/psa_ipc/caller/sp/psa_ipc_caller.c162
-rw-r--r--components/rpc/psa_ipc/caller/sp/psa_ipc_caller.h27
-rw-r--r--components/rpc/psa_ipc/component.cmake24
-rw-r--r--components/rpc/psa_ipc/service_psa_ipc.c244
-rw-r--r--components/rpc/psa_ipc/service_psa_ipc_openamp_lib.h132
-rw-r--r--components/rpc/ts_rpc/caller/linux/component.cmake23
-rw-r--r--components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.c363
-rw-r--r--components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.h26
-rw-r--r--components/rpc/ts_rpc/caller/sp/component.cmake18
-rw-r--r--components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.c523
-rw-r--r--components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.h33
-rw-r--r--components/rpc/ts_rpc/common/component.cmake18
-rw-r--r--components/rpc/ts_rpc/common/test/test_ts_rpc_abi.cpp191
-rw-r--r--components/rpc/ts_rpc/common/ts_rpc_abi.c207
-rw-r--r--components/rpc/ts_rpc/common/ts_rpc_abi.h83
-rw-r--r--components/rpc/ts_rpc/endpoint/sp/component.cmake18
-rw-r--r--components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.c339
-rw-r--r--components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h98
-rw-r--r--components/service/attestation/claims/sources/event_log/event_log_claim_source.c6
-rw-r--r--components/service/attestation/claims/sources/implementation_id/implementation_id_claim_source.c4
-rw-r--r--components/service/attestation/client/provision/attest_provision_client.c55
-rw-r--r--components/service/attestation/client/provision/attest_provision_client.h4
-rw-r--r--components/service/attestation/client/psa/iat_client.c149
-rw-r--r--components/service/attestation/client/psa/iat_client.h4
-rw-r--r--components/service/attestation/client/psa_ipc/component.cmake13
-rw-r--r--components/service/attestation/client/psa_ipc/iat_ipc_client.c86
-rw-r--r--components/service/attestation/key_mngr/stub/stub_attest_key_mngr.c11
-rw-r--r--components/service/attestation/provider/attest_provider.c276
-rw-r--r--components/service/attestation/provider/attest_provider.h20
-rw-r--r--components/service/attestation/provider/attestation_uuid.h21
-rw-r--r--components/service/attestation/provider/serializer/attest_provider_serializer.h36
-rw-r--r--components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.c197
-rw-r--r--components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h2
-rw-r--r--components/service/attestation/reporter/eat/eat_serializer.c4
-rw-r--r--components/service/attestation/reporter/psa_ipc/component.cmake13
-rw-r--r--components/service/attestation/reporter/psa_ipc/psa_ipc_attest_report.c45
-rw-r--r--components/service/attestation/reporter/stub/stub_attest_report.c6
-rw-r--r--components/service/attestation/test/component/attestation_reporter_tests.cpp4
-rw-r--r--components/service/attestation/test/service/attestation_provisioning_tests.cpp31
-rw-r--r--components/service/attestation/test/service/attestation_service_tests.cpp31
-rw-r--r--components/service/block_storage/block_store/block_store.c107
-rw-r--r--components/service/block_storage/block_store/block_store.h262
-rw-r--r--components/service/block_storage/block_store/client/block_storage_client.c391
-rw-r--r--components/service/block_storage/block_store/client/block_storage_client.h57
-rw-r--r--components/service/block_storage/block_store/client/component.cmake13
-rw-r--r--components/service/block_storage/block_store/component.cmake15
-rw-r--r--components/service/block_storage/block_store/device/block_device.c110
-rw-r--r--components/service/block_storage/block_store/device/block_device.h149
-rw-r--r--components/service/block_storage/block_store/device/component.cmake13
-rw-r--r--components/service/block_storage/block_store/device/file/component.cmake13
-rw-r--r--components/service/block_storage/block_store/device/file/file_block_store.c349
-rw-r--r--components/service/block_storage/block_store/device/file/file_block_store.h71
-rw-r--r--components/service/block_storage/block_store/device/file/test/component.cmake13
-rw-r--r--components/service/block_storage/block_store/device/file/test/file_block_store_tests.cpp166
-rw-r--r--components/service/block_storage/block_store/device/fvb/FirmwareVolumeBlock.h372
-rw-r--r--components/service/block_storage/block_store/device/fvb/component.cmake13
-rw-r--r--components/service/block_storage/block_store/device/fvb/fvb_block_store.c241
-rw-r--r--components/service/block_storage/block_store/device/fvb/fvb_block_store.h57
-rw-r--r--components/service/block_storage/block_store/device/null/component.cmake13
-rw-r--r--components/service/block_storage/block_store/device/null/null_block_store.c167
-rw-r--r--components/service/block_storage/block_store/device/null/null_block_store.h58
-rw-r--r--components/service/block_storage/block_store/device/ram/component.cmake13
-rw-r--r--components/service/block_storage/block_store/device/ram/ram_block_store.c262
-rw-r--r--components/service/block_storage/block_store/device/ram/ram_block_store.h79
-rw-r--r--components/service/block_storage/block_store/device/ram/test/component.cmake13
-rw-r--r--components/service/block_storage/block_store/device/ram/test/ram_block_store_tests.cpp191
-rw-r--r--components/service/block_storage/block_store/device/rpmb/component.cmake13
-rw-r--r--components/service/block_storage/block_store/device/rpmb/rpmb_block_store.c204
-rw-r--r--components/service/block_storage/block_store/device/rpmb/rpmb_block_store.h56
-rw-r--r--components/service/block_storage/block_store/device/semihosting/component.cmake17
-rw-r--r--components/service/block_storage/block_store/device/semihosting/semihosting_block_store.c425
-rw-r--r--components/service/block_storage/block_store/device/semihosting/semihosting_block_store.h86
-rw-r--r--components/service/block_storage/block_store/device/semihosting/test/component.cmake14
-rw-r--r--components/service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.c277
-rw-r--r--components/service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.h12
-rw-r--r--components/service/block_storage/block_store/partitioned/component.cmake13
-rw-r--r--components/service/block_storage/block_store/partitioned/partitioned_block_store.c407
-rw-r--r--components/service/block_storage/block_store/partitioned/partitioned_block_store.h151
-rw-r--r--components/service/block_storage/block_store/partitioned/test/component.cmake13
-rw-r--r--components/service/block_storage/block_store/partitioned/test/partitioned_block_store_tests.cpp347
-rw-r--r--components/service/block_storage/block_store/storage_partition.c111
-rw-r--r--components/service/block_storage/block_store/storage_partition.h173
-rw-r--r--components/service/block_storage/block_store/storage_partition_acl.c93
-rw-r--r--components/service/block_storage/block_store/storage_partition_acl.h128
-rw-r--r--components/service/block_storage/config/gpt/component.cmake13
-rw-r--r--components/service/block_storage/config/gpt/gpt_partition_configurator.c102
-rw-r--r--components/service/block_storage/config/gpt/gpt_partition_configurator.h37
-rw-r--r--components/service/block_storage/config/ref/component.cmake13
-rw-r--r--components/service/block_storage/config/ref/ref_partition_configurator.c58
-rw-r--r--components/service/block_storage/config/ref/ref_partition_configurator.h59
-rw-r--r--components/service/block_storage/factory/block_store_factory.h69
-rw-r--r--components/service/block_storage/factory/client/block_store_factory.c80
-rw-r--r--components/service/block_storage/factory/client/block_store_factory.h43
-rw-r--r--components/service/block_storage/factory/client/component.cmake13
-rw-r--r--components/service/block_storage/factory/file/block_store_factory.c139
-rw-r--r--components/service/block_storage/factory/file/block_store_factory.h52
-rw-r--r--components/service/block_storage/factory/file/component.cmake20
-rw-r--r--components/service/block_storage/factory/ref_ram/block_store_factory.c78
-rw-r--r--components/service/block_storage/factory/ref_ram/block_store_factory.h42
-rw-r--r--components/service/block_storage/factory/ref_ram/component.cmake20
-rw-r--r--components/service/block_storage/factory/ref_ram_gpt/block_store_factory.c124
-rw-r--r--components/service/block_storage/factory/ref_ram_gpt/block_store_factory.h42
-rw-r--r--components/service/block_storage/factory/ref_ram_gpt/component.cmake20
-rw-r--r--components/service/block_storage/factory/rpmb/block_store_factory.c143
-rw-r--r--components/service/block_storage/factory/rpmb/block_store_factory.h42
-rw-r--r--components/service/block_storage/factory/rpmb/component.cmake20
-rw-r--r--components/service/block_storage/factory/semihosting/block_store_factory.c127
-rw-r--r--components/service/block_storage/factory/semihosting/block_store_factory.h46
-rw-r--r--components/service/block_storage/factory/semihosting/component.cmake20
-rw-r--r--components/service/block_storage/provider/block_storage_provider.c280
-rw-r--r--components/service/block_storage/provider/block_storage_provider.h43
-rw-r--r--components/service/block_storage/provider/block_storage_uuid.h21
-rw-r--r--components/service/block_storage/provider/component.cmake13
-rw-r--r--components/service/block_storage/provider/serializer/block_storage_serializer.h67
-rw-r--r--components/service/block_storage/provider/serializer/packed-c/component.cmake13
-rw-r--r--components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.c226
-rw-r--r--components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h26
-rw-r--r--components/service/block_storage/test/service/block_storage_service_tests.cpp212
-rw-r--r--components/service/block_storage/test/service/component.cmake13
-rw-r--r--components/service/common/client/service_client.c27
-rw-r--r--components/service/common/client/service_client.h8
-rw-r--r--components/service/common/include/psa/client.h248
-rw-r--r--components/service/common/include/psa/crypto_sid.h241
-rw-r--r--components/service/common/include/psa/sid.h78
-rw-r--r--components/service/common/provider/service_provider.c33
-rw-r--r--components/service/common/provider/service_provider.h24
-rw-r--r--components/service/common/provider/test/service_framework_tests.cpp175
-rw-r--r--components/service/common/serializer/protobuf/pb_helper.h2
-rw-r--r--components/service/crypto/backend/mbedcrypto/component.cmake17
-rw-r--r--components/service/crypto/backend/mbedcrypto/config_mbedtls_user.h33
-rw-r--r--components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/component.cmake16
-rw-r--r--components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/mbedtls_fake_x509.c76
-rw-r--r--components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/mbedtls_fake_x509.h11
-rw-r--r--components/service/crypto/backend/mbedcrypto/trng_adapter/linux/linux_trng_adapter.c19
-rw-r--r--components/service/crypto/backend/mbedcrypto/trng_adapter/platform/component.cmake4
-rw-r--r--components/service/crypto/backend/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c15
-rw-r--r--components/service/crypto/backend/psa_ipc/component.cmake21
-rw-r--r--components/service/crypto/backend/psa_ipc/crypto_ipc_backend.c26
-rw-r--r--components/service/crypto/backend/psa_ipc/crypto_ipc_backend.h71
-rw-r--r--components/service/crypto/backend/stub/stub_crypto_backend.c17
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller.h23
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_aead.h194
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_decrypt.h14
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_encrypt.h15
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_cipher.h84
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_copy_key.h16
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_destroy_key.h41
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_export_key.h15
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_export_public_key.h15
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_generate_key.h15
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_generate_random.h15
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_get_key_attributes.h15
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_hash.h101
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_import_key.h14
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_key_derivation.h151
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_mac.h68
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_purge_key.h13
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_sign_hash.h42
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_verify_hash.h44
-rw-r--r--components/service/crypto/client/caller/packed-c/crypto_caller_verify_pkcs7_signature.h90
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller.h34
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_aead.h543
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_decrypt.h76
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_encrypt.h76
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_cipher.h244
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_copy_key.h57
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_destroy_key.h51
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_export_key.h59
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_export_public_key.h59
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_key.h55
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_random.h57
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_get_key_attributes.h56
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_hash.h222
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_import_key.h57
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_key_attributes.h51
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_key_derivation.h298
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_mac.h207
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_purge_key.h51
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_sign_hash.h99
-rw-r--r--components/service/crypto/client/caller/psa_ipc/crypto_caller_verify_hash.h86
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_aead.h97
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_asymmetric_decrypt.h13
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_asymmetric_encrypt.h13
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_cipher.h42
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_copy_key.h7
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_destroy_key.h5
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_export_key.h8
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_export_public_key.h8
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_generate_key.h6
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_generate_random.h6
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_get_key_attributes.h6
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_hash.h46
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_import_key.h8
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_key_derivation.h54
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_mac.h33
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_purge_key.h5
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_sign_hash.h20
-rw-r--r--components/service/crypto/client/caller/stub/crypto_caller_verify_hash.h19
-rw-r--r--components/service/crypto/client/cpp/component.cmake10
-rw-r--r--components/service/crypto/client/cpp/crypto_client.cpp19
-rw-r--r--components/service/crypto/client/cpp/crypto_client.h26
-rw-r--r--components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp36
-rw-r--r--components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h23
-rw-r--r--components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp363
-rw-r--r--components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h34
-rw-r--r--components/service/crypto/client/psa/component.cmake1
-rw-r--r--components/service/crypto/client/psa/crypto_client.h16
-rw-r--r--components/service/crypto/client/psa/psa_aead.c243
-rw-r--r--components/service/crypto/client/psa/psa_cipher.c98
-rw-r--r--components/service/crypto/client/psa/psa_crypto_client.c10
-rw-r--r--components/service/crypto/client/psa/psa_crypto_client.h2
-rw-r--r--components/service/crypto/client/psa/psa_hash.c27
-rw-r--r--components/service/crypto/client/psa/psa_mac.c20
-rw-r--r--components/service/crypto/client/psa/psa_sign_message.c24
-rw-r--r--components/service/crypto/client/psa/psa_verify_message.c24
-rw-r--r--components/service/crypto/client/psa/verify_pkcs7_signature.c21
-rw-r--r--components/service/crypto/client/test/standalone/standalone_crypto_client.cpp56
-rw-r--r--components/service/crypto/client/test/standalone/standalone_crypto_client.h7
-rw-r--r--components/service/crypto/factory/crypto_provider_factory.h2
-rw-r--r--components/service/crypto/factory/full/crypto_provider_factory.c44
-rw-r--r--components/service/crypto/include/psa/crypto_client_struct.h10
-rw-r--r--components/service/crypto/include/psa/crypto_sizes.h4
-rw-r--r--components/service/crypto/include/psa/crypto_struct.h12
-rw-r--r--components/service/crypto/provider/crypto_provider.c535
-rw-r--r--components/service/crypto/provider/crypto_provider.h10
-rw-r--r--components/service/crypto/provider/crypto_uuid.h24
-rw-r--r--components/service/crypto/provider/extension/aead/aead_provider.c167
-rw-r--r--components/service/crypto/provider/extension/aead/aead_provider.h2
-rw-r--r--components/service/crypto/provider/extension/aead/serializer/aead_provider_serializer.h30
-rw-r--r--components/service/crypto/provider/extension/aead/serializer/packed-c/packedc_aead_provider_serializer.c125
-rw-r--r--components/service/crypto/provider/extension/cipher/cipher_provider.c119
-rw-r--r--components/service/crypto/provider/extension/cipher/cipher_provider.h2
-rw-r--r--components/service/crypto/provider/extension/cipher/serializer/cipher_provider_serializer.h22
-rw-r--r--components/service/crypto/provider/extension/cipher/serializer/packed-c/packedc_cipher_provider_serializer.c98
-rw-r--r--components/service/crypto/provider/extension/hash/hash_provider.c120
-rw-r--r--components/service/crypto/provider/extension/hash/hash_provider.h2
-rw-r--r--components/service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h20
-rw-r--r--components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.c82
-rw-r--r--components/service/crypto/provider/extension/key_derivation/key_derivation_provider.c171
-rw-r--r--components/service/crypto/provider/extension/key_derivation/key_derivation_provider.h2
-rw-r--r--components/service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h42
-rw-r--r--components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.c136
-rw-r--r--components/service/crypto/provider/extension/mac/mac_provider.c106
-rw-r--r--components/service/crypto/provider/extension/mac/mac_provider.h2
-rw-r--r--components/service/crypto/provider/extension/mac/serializer/mac_provider_serializer.h16
-rw-r--r--components/service/crypto/provider/extension/mac/serializer/packed-c/packedc_mac_provider_serializer.c66
-rw-r--r--components/service/crypto/provider/serializer/crypto_provider_serializer.h204
-rw-r--r--components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c1090
-rw-r--r--components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c821
-rw-r--r--components/service/crypto/test/protocol/check_crypto_opcode_alignment.cpp25
-rw-r--r--components/service/crypto/test/service/crypto_service_limit_tests.cpp43
-rw-r--r--components/service/crypto/test/service/crypto_service_scenarios.cpp284
-rw-r--r--components/service/crypto/test/service/crypto_service_scenarios.h4
-rw-r--r--components/service/crypto/test/service/extension/cipher/packed-c/cipher_service_packedc_tests.cpp31
-rw-r--r--components/service/crypto/test/service/extension/hash/hash_service_scenarios.cpp5
-rw-r--r--components/service/crypto/test/service/extension/hash/packed-c/hash_service_packedc_tests.cpp31
-rw-r--r--components/service/crypto/test/service/extension/key_derivation/packed-c/key_derivation_service_packedc_tests.cpp31
-rw-r--r--components/service/crypto/test/service/extension/mac/packed-c/mac_service_packedc_tests.cpp31
-rw-r--r--components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp39
-rw-r--r--components/service/crypto/test/service/protobuf/crypto_service_protobuf_tests.cpp34
-rw-r--r--components/service/discovery/client/discovery_client.c60
-rw-r--r--components/service/discovery/client/discovery_client.h37
-rw-r--r--components/service/discovery/provider/discovery_info.h66
-rw-r--r--components/service/discovery/provider/discovery_provider.c153
-rw-r--r--components/service/discovery/provider/discovery_provider.h72
-rw-r--r--components/service/discovery/provider/serializer/discovery_provider_serializer.h28
-rw-r--r--components/service/discovery/provider/serializer/packed-c/component.cmake13
-rw-r--r--components/service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.c46
-rw-r--r--components/service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.h26
-rw-r--r--components/service/discovery/test/service/component.cmake13
-rw-r--r--components/service/discovery/test/service/discovery_service_tests.cpp65
-rw-r--r--components/service/fwu/agent/component.cmake16
-rw-r--r--components/service/fwu/agent/fw_directory.c102
-rw-r--r--components/service/fwu/agent/fw_directory.h193
-rw-r--r--components/service/fwu/agent/img_dir_serializer.c72
-rw-r--r--components/service/fwu/agent/img_dir_serializer.h55
-rw-r--r--components/service/fwu/agent/install_type.h51
-rw-r--r--components/service/fwu/agent/stream_manager.c277
-rw-r--r--components/service/fwu/agent/stream_manager.h197
-rw-r--r--components/service/fwu/agent/update_agent.c307
-rw-r--r--components/service/fwu/agent/update_agent.h188
-rw-r--r--components/service/fwu/config/component.cmake13
-rw-r--r--components/service/fwu/config/fwu_configure.c70
-rw-r--r--components/service/fwu/config/fwu_configure.h45
-rw-r--r--components/service/fwu/config/gpt/component.cmake13
-rw-r--r--components/service/fwu/config/gpt/gpt_fwu_configure.c245
-rw-r--r--components/service/fwu/config/gpt/gpt_fwu_configure.h42
-rw-r--r--components/service/fwu/fw_store/banked/bank_scheme.h40
-rw-r--r--components/service/fwu/fw_store/banked/bank_tracker.c99
-rw-r--r--components/service/fwu/fw_store/banked/bank_tracker.h133
-rw-r--r--components/service/fwu/fw_store/banked/banked_fw_store.c497
-rw-r--r--components/service/fwu/fw_store/banked/banked_fw_store.h68
-rw-r--r--components/service/fwu/fw_store/banked/component.cmake15
-rw-r--r--components/service/fwu/fw_store/banked/metadata_manager.c299
-rw-r--r--components/service/fwu/fw_store/banked/metadata_manager.h151
-rw-r--r--components/service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h100
-rw-r--r--components/service/fwu/fw_store/banked/metadata_serializer/v1/component.cmake13
-rw-r--r--components/service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.c175
-rw-r--r--components/service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h30
-rw-r--r--components/service/fwu/fw_store/banked/metadata_serializer/v2/component.cmake13
-rw-r--r--components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.c253
-rw-r--r--components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h30
-rw-r--r--components/service/fwu/fw_store/banked/test/component.cmake14
-rw-r--r--components/service/fwu/fw_store/banked/test/metadata_manager_tests.cpp186
-rw-r--r--components/service/fwu/fw_store/banked/test/metadata_v2_tests.cpp63
-rw-r--r--components/service/fwu/fw_store/banked/volume_id.h74
-rw-r--r--components/service/fwu/fw_store/fw_store.h188
-rw-r--r--components/service/fwu/inspector/direct/component.cmake13
-rw-r--r--components/service/fwu/inspector/direct/direct_fw_inspector.c66
-rw-r--r--components/service/fwu/inspector/direct/direct_fw_inspector.h37
-rw-r--r--components/service/fwu/inspector/fw_inspector.h44
-rw-r--r--components/service/fwu/inspector/mock/component.cmake13
-rw-r--r--components/service/fwu/inspector/mock/mock_fw_inspector.c65
-rw-r--r--components/service/fwu/inspector/mock/mock_fw_inspector.h43
-rw-r--r--components/service/fwu/installer/component.cmake27
-rw-r--r--components/service/fwu/installer/copy/component.cmake16
-rw-r--r--components/service/fwu/installer/copy/copy_installer.c210
-rw-r--r--components/service/fwu/installer/copy/copy_installer.h60
-rw-r--r--components/service/fwu/installer/copy/test/component.cmake13
-rw-r--r--components/service/fwu/installer/copy/test/copy_installer_tests.cpp226
-rw-r--r--components/service/fwu/installer/factory/default/component.cmake13
-rw-r--r--components/service/fwu/installer/factory/default/installer_factory.c104
-rw-r--r--components/service/fwu/installer/factory/default/test/component.cmake13
-rw-r--r--components/service/fwu/installer/factory/default/test/default_installer_factory_tests.cpp123
-rw-r--r--components/service/fwu/installer/factory/installer_factory.h55
-rw-r--r--components/service/fwu/installer/factory/locations.h32
-rw-r--r--components/service/fwu/installer/installer.c121
-rw-r--r--components/service/fwu/installer/installer.h192
-rw-r--r--components/service/fwu/installer/installer_index.c137
-rw-r--r--components/service/fwu/installer/installer_index.h98
-rw-r--r--components/service/fwu/installer/raw/component.cmake16
-rw-r--r--components/service/fwu/installer/raw/raw_installer.c219
-rw-r--r--components/service/fwu/installer/raw/raw_installer.h65
-rw-r--r--components/service/fwu/installer/raw/test/component.cmake13
-rw-r--r--components/service/fwu/installer/raw/test/raw_installer_tests.cpp220
-rw-r--r--components/service/fwu/provider/component.cmake13
-rw-r--r--components/service/fwu/provider/fwu_provider.c242
-rw-r--r--components/service/fwu/provider/fwu_provider.h71
-rw-r--r--components/service/fwu/provider/fwu_uuid.h21
-rw-r--r--components/service/fwu/provider/serializer/fwu_provider_serializer.h58
-rw-r--r--components/service/fwu/provider/serializer/packed-c/component.cmake13
-rw-r--r--components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.c190
-rw-r--r--components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h25
-rw-r--r--components/service/fwu/test/fwu_client/direct/component.cmake13
-rw-r--r--components/service/fwu/test/fwu_client/direct/direct_fwu_client.cpp81
-rw-r--r--components/service/fwu/test/fwu_client/direct/direct_fwu_client.h51
-rw-r--r--components/service/fwu/test/fwu_client/fwu_client.h50
-rw-r--r--components/service/fwu/test/fwu_client/remote/component.cmake13
-rw-r--r--components/service/fwu/test/fwu_client/remote/remote_fwu_client.cpp359
-rw-r--r--components/service/fwu/test/fwu_client/remote/remote_fwu_client.h53
-rw-r--r--components/service/fwu/test/fwu_dut/component.cmake (renamed from components/rpc/common/demux/component.cmake)4
-rw-r--r--components/service/fwu/test/fwu_dut/fwu_dut.cpp108
-rw-r--r--components/service/fwu/test/fwu_dut/fwu_dut.h135
-rw-r--r--components/service/fwu/test/fwu_dut/proxy/component.cmake13
-rw-r--r--components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.cpp61
-rw-r--r--components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h45
-rw-r--r--components/service/fwu/test/fwu_dut/sim/component.cmake22
-rw-r--r--components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp475
-rw-r--r--components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h127
-rw-r--r--components/service/fwu/test/fwu_dut_factory/fwu_dut_factory.h34
-rw-r--r--components/service/fwu/test/fwu_dut_factory/remote/component.cmake13
-rw-r--r--components/service/fwu/test/fwu_dut_factory/remote/fwu_dut_factory.cpp25
-rw-r--r--components/service/fwu/test/fwu_dut_factory/remote_sim/component.cmake13
-rw-r--r--components/service/fwu/test/fwu_dut_factory/remote_sim/fwu_dut_factory.cpp36
-rw-r--r--components/service/fwu/test/fwu_dut_factory/sim/component.cmake13
-rw-r--r--components/service/fwu/test/fwu_dut_factory/sim/fwu_dut_factory.cpp20
-rw-r--r--components/service/fwu/test/image_directory_checker/component.cmake13
-rw-r--r--components/service/fwu/test/image_directory_checker/image_directory_checker.cpp131
-rw-r--r--components/service/fwu/test/image_directory_checker/image_directory_checker.h46
-rw-r--r--components/service/fwu/test/metadata_checker/component.cmake15
-rw-r--r--components/service/fwu/test/metadata_checker/metadata_checker.cpp36
-rw-r--r--components/service/fwu/test/metadata_checker/metadata_checker.h47
-rw-r--r--components/service/fwu/test/metadata_checker/metadata_checker_v1.cpp104
-rw-r--r--components/service/fwu/test/metadata_checker/metadata_checker_v1.h37
-rw-r--r--components/service/fwu/test/metadata_checker/metadata_checker_v2.cpp102
-rw-r--r--components/service/fwu/test/metadata_checker/metadata_checker_v2.h35
-rw-r--r--components/service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.cpp53
-rw-r--r--components/service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.h37
-rw-r--r--components/service/fwu/test/metadata_fetcher/client/component.cmake13
-rw-r--r--components/service/fwu/test/metadata_fetcher/metadata_fetcher.h33
-rw-r--r--components/service/fwu/test/metadata_fetcher/volume/component.cmake13
-rw-r--r--components/service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.cpp56
-rw-r--r--components/service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.h33
-rw-r--r--components/service/fwu/test/ref_scenarios/component.cmake19
-rw-r--r--components/service/fwu/test/ref_scenarios/image_directory_tests.cpp242
-rw-r--r--components/service/fwu/test/ref_scenarios/invalid_behaviour_tests.cpp263
-rw-r--r--components/service/fwu/test/ref_scenarios/oversize_image_tests.cpp266
-rw-r--r--components/service/fwu/test/ref_scenarios/power_failure_tests.cpp210
-rw-r--r--components/service/fwu/test/ref_scenarios/rollback_tests.cpp253
-rw-r--r--components/service/fwu/test/ref_scenarios/update_fmp_tests.cpp283
-rw-r--r--components/service/fwu/test/ref_scenarios/update_scenario_tests.cpp227
-rw-r--r--components/service/fwu/test/service/component.cmake13
-rw-r--r--components/service/fwu/test/service/fwu_service_tests.cpp78
-rw-r--r--components/service/locator/interface/component.cmake7
-rw-r--r--components/service/locator/interface/service_locator.h19
-rw-r--r--components/service/locator/linux/ffa/linuxffa_location_strategy.c207
-rw-r--r--components/service/locator/linux/ffa/linuxffa_location_strategy.h8
-rw-r--r--components/service/locator/linux/ffa/linuxffa_service_context.c130
-rw-r--r--components/service/locator/linux/ffa/linuxffa_service_context.h19
-rw-r--r--components/service/locator/linux/linux_env.c2
-rw-r--r--components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.c68
-rw-r--r--components/service/locator/linux/mm_communicate/mm_communicate_service_context.c108
-rw-r--r--components/service/locator/linux/mm_communicate/mm_communicate_service_context.h2
-rw-r--r--components/service/locator/remote/restapi/component.cmake28
-rw-r--r--components/service/locator/remote/restapi/restapi_env.c19
-rw-r--r--components/service/locator/remote/restapi/restapi_location.h17
-rw-r--r--components/service/locator/remote/restapi/restapi_location_strategy.c104
-rw-r--r--components/service/locator/remote/restapi/restapi_location_strategy.h27
-rw-r--r--components/service/locator/remote/restapi/restapi_service_context.c95
-rw-r--r--components/service/locator/remote/restapi/restapi_service_context.h32
-rw-r--r--components/service/locator/service_locator.c51
-rw-r--r--components/service/locator/service_name.c2
-rw-r--r--components/service/locator/sp/ffa/spffa_location_strategy.c87
-rw-r--r--components/service/locator/sp/ffa/spffa_location_strategy.h2
-rw-r--r--components/service/locator/sp/ffa/spffa_service_context.c95
-rw-r--r--components/service/locator/sp/ffa/spffa_service_context.h10
-rw-r--r--components/service/locator/sp/sp_env.c2
-rw-r--r--components/service/locator/standalone/services/attestation/attestation_service_context.cpp5
-rw-r--r--components/service/locator/standalone/services/block-storage/block_storage_service_context.cpp48
-rw-r--r--components/service/locator/standalone/services/block-storage/block_storage_service_context.h30
-rw-r--r--components/service/locator/standalone/services/block-storage/component.cmake13
-rw-r--r--components/service/locator/standalone/services/crypto/crypto_service_context.cpp32
-rw-r--r--components/service/locator/standalone/services/crypto/crypto_service_context.h5
-rw-r--r--components/service/locator/standalone/services/fwu/component.cmake13
-rw-r--r--components/service/locator/standalone/services/fwu/fwu_service_context.cpp38
-rw-r--r--components/service/locator/standalone/services/fwu/fwu_service_context.h37
-rw-r--r--components/service/locator/standalone/services/internal-trusted-storage/its_service_context.cpp5
-rw-r--r--components/service/locator/standalone/services/protected-storage/ps_service_context.cpp47
-rw-r--r--components/service/locator/standalone/services/protected-storage/ps_service_context.h21
-rw-r--r--components/service/locator/standalone/services/rpmb/component.cmake13
-rw-r--r--components/service/locator/standalone/services/rpmb/rpmb_service_context.cpp44
-rw-r--r--components/service/locator/standalone/services/rpmb/rpmb_service_context.h33
-rw-r--r--components/service/locator/standalone/services/smm-variable/smm_variable_service_context.cpp50
-rw-r--r--components/service/locator/standalone/services/smm-variable/smm_variable_service_context.h6
-rw-r--r--components/service/locator/standalone/services/test-runner/test_runner_service_context.cpp2
-rw-r--r--components/service/locator/standalone/standalone_env.cpp20
-rw-r--r--components/service/locator/standalone/standalone_location_strategy.cpp13
-rw-r--r--components/service/locator/standalone/standalone_service_context.cpp78
-rw-r--r--components/service/locator/standalone/standalone_service_context.h24
-rw-r--r--components/service/locator/standalone/standalone_service_registry.cpp3
-rw-r--r--components/service/locator/standalone/standalone_service_registry.h2
-rw-r--r--components/service/rpmb/backend/component.cmake13
-rw-r--r--components/service/rpmb/backend/emulated/component.cmake14
-rw-r--r--components/service/rpmb/backend/emulated/rpmb_backend_emulated.c377
-rw-r--r--components/service/rpmb/backend/emulated/rpmb_backend_emulated.h54
-rw-r--r--components/service/rpmb/backend/mock/component.cmake13
-rw-r--r--components/service/rpmb/backend/mock/rpmb_backend_mock.cpp90
-rw-r--r--components/service/rpmb/backend/mock/rpmb_backend_mock.h42
-rw-r--r--components/service/rpmb/backend/mock/test/component.cmake13
-rw-r--r--components/service/rpmb/backend/mock/test/test_rpmb_backend_mock.cpp66
-rw-r--r--components/service/rpmb/backend/rpmb_backend.c23
-rw-r--r--components/service/rpmb/backend/rpmb_backend.h158
-rw-r--r--components/service/rpmb/client/component.cmake13
-rw-r--r--components/service/rpmb/client/rpmb_client.c164
-rw-r--r--components/service/rpmb/client/rpmb_client.h48
-rw-r--r--components/service/rpmb/frontend/component.cmake23
-rw-r--r--components/service/rpmb/frontend/platform/default/component.cmake13
-rw-r--r--components/service/rpmb/frontend/platform/default/rpmb_platform_default.c120
-rw-r--r--components/service/rpmb/frontend/platform/default/rpmb_platform_default.h28
-rw-r--r--components/service/rpmb/frontend/platform/mock/component.cmake13
-rw-r--r--components/service/rpmb/frontend/platform/mock/rpmb_platform_mock.cpp101
-rw-r--r--components/service/rpmb/frontend/platform/mock/rpmb_platform_mock.h44
-rw-r--r--components/service/rpmb/frontend/platform/mock/test/component.cmake13
-rw-r--r--components/service/rpmb/frontend/platform/mock/test/test_rpmb_platform_mock.cpp73
-rw-r--r--components/service/rpmb/frontend/rpmb_frontend.c398
-rw-r--r--components/service/rpmb/frontend/rpmb_frontend.h175
-rw-r--r--components/service/rpmb/frontend/test/component.cmake13
-rw-r--r--components/service/rpmb/frontend/test/test_rpmb_frontend.cpp1065
-rw-r--r--components/service/rpmb/provider/component.cmake13
-rw-r--r--components/service/rpmb/provider/rpmb_provider.c128
-rw-r--r--components/service/rpmb/provider/rpmb_provider.h48
-rw-r--r--components/service/rpmb/provider/rpmb_uuid.h21
-rw-r--r--components/service/secure_storage/backend/mock_store/mock_store.c67
-rw-r--r--components/service/secure_storage/backend/mock_store/test/mock_store_tests.cpp4
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/component.cmake13
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.c239
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.h82
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/component.cmake5
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/ram/component.cmake18
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_info.c (renamed from components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_info.c)17
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.c (renamed from components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_ram.c)2
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.h (renamed from components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_ram.h)25
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.c9
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.h9
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/secure_flash_store.c58
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/secure_flash_store.h7
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/test/component.cmake6
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/test/sfs_block_store_tests.cpp85
-rw-r--r--components/service/secure_storage/backend/secure_flash_store/test/sfs_ram_tests.cpp (renamed from components/service/secure_storage/backend/secure_flash_store/test/sfs_tests.cpp)21
-rw-r--r--components/service/secure_storage/backend/secure_storage_client/secure_storage_client.c516
-rw-r--r--components/service/secure_storage/backend/secure_storage_client/secure_storage_client.h2
-rw-r--r--components/service/secure_storage/backend/secure_storage_client/test/secure_storage_client_tests.cpp28
-rw-r--r--components/service/secure_storage/backend/secure_storage_client/test/secure_storage_proxy_tests.cpp44
-rw-r--r--components/service/secure_storage/backend/secure_storage_ipc/component.cmake14
-rw-r--r--components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c196
-rw-r--r--components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h53
-rw-r--r--components/service/secure_storage/factory/common/sfs/storage_factory.c6
-rw-r--r--components/service/secure_storage/factory/sp/optee_trusted_store/storage_factory.c102
-rw-r--r--components/service/secure_storage/factory/sp/rot_store/storage_factory.c93
-rw-r--r--components/service/secure_storage/factory/sp/sfs_shared_block_store/component.cmake (renamed from components/service/secure_storage/factory/sp/optee_trusted_store/component.cmake)2
-rw-r--r--components/service/secure_storage/factory/sp/sfs_shared_block_store/storage_factory.c112
-rw-r--r--components/service/secure_storage/frontend/psa/its/test/its_api_tests.cpp5
-rw-r--r--components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.cpp9
-rw-r--r--components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.h2
-rw-r--r--components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.c238
-rw-r--r--components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h9
-rw-r--r--components/service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h23
-rw-r--r--components/service/secure_storage/include/psa/storage_common.h6
-rw-r--r--components/service/secure_storage/test/service/its_service_tests.cpp31
-rw-r--r--components/service/secure_storage/test/service/ps_service_tests.cpp33
-rw-r--r--components/service/smm_variable/backend/test/variable_store_tests.cpp646
-rw-r--r--components/service/smm_variable/backend/uefi_variable_store.c697
-rw-r--r--components/service/smm_variable/backend/variable_index.c434
-rw-r--r--components/service/smm_variable/backend/variable_index_iterator.c59
-rw-r--r--components/service/smm_variable/client/cpp/smm_variable_client.cpp600
-rw-r--r--components/service/smm_variable/client/cpp/smm_variable_client.h118
-rw-r--r--components/service/smm_variable/provider/smm_variable_provider.c361
-rw-r--r--components/service/smm_variable/test/service/smm_variable_service_tests.cpp430
-rw-r--r--components/service/spm_test/optee_sp_user_defines.h (renamed from deployments/internal-trusted-storage/opteesp/optee_sp_user_defines.h)4
-rw-r--r--components/service/spm_test/sp.c1031
-rw-r--r--components/service/spm_test/spm_test.cmake73
-rw-r--r--components/service/test_runner/client/cpp/test_runner_client.cpp31
-rw-r--r--components/service/test_runner/client/cpp/test_runner_client.h4
-rw-r--r--components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c6
-rw-r--r--components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c268
-rw-r--r--components/service/test_runner/provider/serializer/test_runner_provider_serializer.h26
-rw-r--r--components/service/test_runner/provider/test_runner_provider.c254
-rw-r--r--components/service/test_runner/provider/test_runner_provider.h5
-rw-r--r--components/service/test_runner/provider/test_runner_uuid.h21
-rw-r--r--components/service/test_runner/test/service/test_runner_service_tests.cpp29
-rw-r--r--components/service/uefi/smm_variable/backend/component.cmake (renamed from components/service/smm_variable/backend/component.cmake)7
-rw-r--r--components/service/uefi/smm_variable/backend/direct/component.cmake13
-rw-r--r--components/service/uefi/smm_variable/backend/direct/uefi_direct_backend.c48
-rw-r--r--components/service/uefi/smm_variable/backend/test/component.cmake (renamed from components/service/smm_variable/backend/test/component.cmake)0
-rw-r--r--components/service/uefi/smm_variable/backend/test/variable_index_tests.cpp (renamed from components/service/smm_variable/backend/test/variable_index_tests.cpp)368
-rw-r--r--components/service/uefi/smm_variable/backend/test/variable_store_tests.cpp758
-rw-r--r--components/service/uefi/smm_variable/backend/uefi_variable_store.c1590
-rw-r--r--components/service/uefi/smm_variable/backend/uefi_variable_store.h (renamed from components/service/smm_variable/backend/uefi_variable_store.h)106
-rw-r--r--components/service/uefi/smm_variable/backend/variable_checker.c (renamed from components/service/smm_variable/backend/variable_checker.c)30
-rw-r--r--components/service/uefi/smm_variable/backend/variable_checker.h (renamed from components/service/smm_variable/backend/variable_checker.h)37
-rw-r--r--components/service/uefi/smm_variable/backend/variable_index.c327
-rw-r--r--components/service/uefi/smm_variable/backend/variable_index.h (renamed from components/service/smm_variable/backend/variable_index.h)137
-rw-r--r--components/service/uefi/smm_variable/backend/variable_index_iterator.c56
-rw-r--r--components/service/uefi/smm_variable/backend/variable_index_iterator.h (renamed from components/service/smm_variable/backend/variable_index_iterator.h)21
-rw-r--r--components/service/uefi/smm_variable/client/cpp/component.cmake (renamed from components/service/smm_variable/client/cpp/component.cmake)0
-rw-r--r--components/service/uefi/smm_variable/client/cpp/smm_variable_client.cpp642
-rw-r--r--components/service/uefi/smm_variable/client/cpp/smm_variable_client.h130
-rw-r--r--components/service/uefi/smm_variable/frontend/mm_communicate/component.cmake (renamed from components/service/smm_variable/frontend/mm_communicate/component.cmake)0
-rw-r--r--components/service/uefi/smm_variable/frontend/mm_communicate/smm_variable_mm_service.c (renamed from components/service/smm_variable/frontend/mm_communicate/smm_variable_mm_service.c)71
-rw-r--r--components/service/uefi/smm_variable/frontend/mm_communicate/smm_variable_mm_service.h (renamed from components/service/smm_variable/frontend/mm_communicate/smm_variable_mm_service.h)6
-rw-r--r--components/service/uefi/smm_variable/frontend/mm_communicate/test/test_smm_variable_mm_service.cpp (renamed from components/service/smm_variable/frontend/mm_communicate/test/test_smm_variable_mm_service.cpp)184
-rw-r--r--components/service/uefi/smm_variable/frontend/mm_communicate/tests.cmake (renamed from components/service/smm_variable/frontend/mm_communicate/tests.cmake)6
-rw-r--r--components/service/uefi/smm_variable/provider/component.cmake (renamed from components/service/smm_variable/provider/component.cmake)0
-rw-r--r--components/service/uefi/smm_variable/provider/smm_variable_provider.c359
-rw-r--r--components/service/uefi/smm_variable/provider/smm_variable_provider.h (renamed from components/service/smm_variable/provider/smm_variable_provider.h)24
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/KEK.h251
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/KEK_delete.h114
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/PK1.h182
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/PK1_delete.h114
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/PK2.h182
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/PK2_delete.h114
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/PK3.h182
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/db1.h182
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/db2.h182
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/var.h283
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/var_data.h181
-rw-r--r--components/service/uefi/smm_variable/test/service/auth_vectors/var_delete.h114
-rw-r--r--components/service/uefi/smm_variable/test/service/component.cmake (renamed from components/service/smm_variable/test/service/component.cmake)0
-rw-r--r--components/service/uefi/smm_variable/test/service/smm_variable_attack_tests.cpp (renamed from components/service/smm_variable/test/service/smm_variable_attack_tests.cpp)191
-rw-r--r--components/service/uefi/smm_variable/test/service/smm_variable_service_tests.cpp972
-rw-r--r--deployments/attestation/attestation.cmake44
-rw-r--r--deployments/attestation/config/default-opteesp/CMakeLists.txt97
-rw-r--r--deployments/attestation/config/default-opteesp/default_attestation.dts.in (renamed from deployments/attestation/opteesp/default_attestation.dts.in)13
-rw-r--r--deployments/attestation/config/default-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/attestation/config/default-sp/CMakeLists.txt97
-rw-r--r--deployments/attestation/config/default-sp/default_attestation.dts.in41
-rw-r--r--deployments/attestation/env/commonsp/attestation_sp.c237
-rw-r--r--deployments/attestation/env/commonsp/attestation_sp.cmake31
-rw-r--r--deployments/attestation/env/commonsp/attestation_sp.h10
-rw-r--r--deployments/attestation/infra/tpm-eventlog-psa.cmake34
-rw-r--r--deployments/attestation/opteesp/CMakeLists.txt163
-rw-r--r--deployments/attestation/opteesp/attestation_sp.c168
-rw-r--r--deployments/attestation/opteesp/attestation_sp.h18
-rw-r--r--deployments/attestation/opteesp/optee_sp_user_defines.h22
-rw-r--r--deployments/block-storage/block-storage.cmake28
-rw-r--r--deployments/block-storage/config/cfi-flash-optee/CMakeLists.txt102
-rw-r--r--deployments/block-storage/config/cfi-flash-optee/default_block-storage.dts.in21
-rw-r--r--deployments/block-storage/config/cfi-flash-optee/optee_sp_user_defines.h14
-rw-r--r--deployments/block-storage/config/default-opteesp/CMakeLists.txt80
-rw-r--r--deployments/block-storage/config/default-opteesp/default_block-storage.dts.in21
-rw-r--r--deployments/block-storage/config/default-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/block-storage/config/default-sp/CMakeLists.txt85
-rw-r--r--deployments/block-storage/config/default-sp/default_block-storage.dts.in26
-rw-r--r--deployments/block-storage/config/edk2-secure-flash-opteesp/CMakeLists.txt103
-rw-r--r--deployments/block-storage/config/edk2-secure-flash-opteesp/default_block-storage.dts.in21
-rw-r--r--deployments/block-storage/config/edk2-secure-flash-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/block-storage/config/semihosted-opteesp/CMakeLists.txt99
-rw-r--r--deployments/block-storage/config/semihosted-opteesp/default_block-storage.dts.in21
-rw-r--r--deployments/block-storage/config/semihosted-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/block-storage/env/commonsp/block_storage_sp.c132
-rw-r--r--deployments/block-storage/env/commonsp/block_storage_sp.cmake32
-rw-r--r--deployments/block-storage/env/commonsp/block_storage_sp.h10
-rw-r--r--deployments/block-storage/infra/ref-ram.cmake24
-rw-r--r--deployments/block-storage/infra/semihosted.cmake34
-rw-r--r--deployments/component-test/arm-linux/CMakeLists.txt7
-rw-r--r--deployments/component-test/component-test.cmake128
-rw-r--r--deployments/component-test/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/crypto/config/default-opteesp/CMakeLists.txt98
-rw-r--r--deployments/crypto/config/default-opteesp/default_crypto.dts.in (renamed from deployments/crypto/opteesp/default_crypto.dts.in)6
-rw-r--r--deployments/crypto/config/default-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/crypto/config/default-sp/CMakeLists.txt98
-rw-r--r--deployments/crypto/config/default-sp/default_crypto.dts.in37
-rw-r--r--deployments/crypto/crypto.cmake65
-rw-r--r--deployments/crypto/env/commonsp/crypto_sp.c158
-rw-r--r--deployments/crypto/env/commonsp/crypto_sp.cmake30
-rw-r--r--deployments/crypto/env/commonsp/crypto_sp.h10
-rw-r--r--deployments/crypto/infra/baremetal-psa.cmake33
-rw-r--r--deployments/crypto/opteesp/.gitignore1
-rw-r--r--deployments/crypto/opteesp/CMakeLists.txt167
-rw-r--r--deployments/crypto/opteesp/crypto_sp.c96
-rw-r--r--deployments/crypto/opteesp/crypto_sp.h18
-rw-r--r--deployments/crypto/opteesp/optee_sp_user_defines.h22
-rw-r--r--deployments/deployment.cmake25
-rw-r--r--deployments/env-test/config/baremetal-fvp_base_revc-opteesp/CMakeLists.txt98
-rw-r--r--deployments/env-test/config/baremetal-fvp_base_revc-opteesp/default_env-test.dts.in59
-rw-r--r--deployments/env-test/config/baremetal-fvp_base_revc-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/env-test/config/baremetal-fvp_base_revc-sp/CMakeLists.txt97
-rw-r--r--deployments/env-test/config/baremetal-fvp_base_revc-sp/default_env-test.dts.in (renamed from deployments/env-test/opteesp/default_env-test.dts.in)14
-rw-r--r--deployments/env-test/config/n1sdp-opteesp/CMakeLists.txt (renamed from deployments/env-test/opteesp/CMakeLists.txt)104
-rw-r--r--deployments/env-test/config/n1sdp-opteesp/default_env-test.dts.in59
-rw-r--r--deployments/env-test/config/n1sdp-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/env-test/env-test.cmake (renamed from deployments/env-test/env_test.cmake)25
-rw-r--r--deployments/env-test/env/commonsp/env_test_sp.c124
-rw-r--r--deployments/env-test/env/commonsp/env_test_sp.cmake31
-rw-r--r--deployments/env-test/env/commonsp/env_test_sp.h10
-rw-r--r--deployments/env-test/opteesp/.gitignore1
-rw-r--r--deployments/env-test/opteesp/env_test.c92
-rw-r--r--deployments/env-test/opteesp/env_test.h18
-rw-r--r--deployments/env-test/opteesp/optee_sp_user_defines.h22
-rw-r--r--deployments/env-test/suites/baremetal-tests.cmake51
-rw-r--r--deployments/env-test/suites/edk2-platform-tests.cmake27
-rw-r--r--deployments/env-test/suites/registration/baremetal_tests.c22
-rw-r--r--deployments/env-test/suites/registration/edk2_platform_tests.c (renamed from deployments/env-test/opteesp/env_test_tests.c)8
-rw-r--r--deployments/env-test/suites/registration/env_test_register.h (renamed from deployments/env-test/opteesp/env_test_tests.h)8
-rw-r--r--deployments/fwu-tool/file-block-store.cmake33
-rw-r--r--deployments/fwu-tool/fwu.cmake55
-rw-r--r--deployments/fwu-tool/linux-pc/CMakeLists.txt59
-rw-r--r--deployments/fwu/config/default-opteesp/CMakeLists.txt96
-rw-r--r--deployments/fwu/config/default-opteesp/default_fwu.dts.in21
-rw-r--r--deployments/fwu/config/default-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/fwu/config/default-sp/CMakeLists.txt97
-rw-r--r--deployments/fwu/config/default-sp/default_fwu.dts.in26
-rw-r--r--deployments/fwu/env/commonsp/fwu_sp.c207
-rw-r--r--deployments/fwu/env/commonsp/fwu_sp.cmake35
-rw-r--r--deployments/fwu/fwu.cmake39
-rw-r--r--deployments/fwu/infra/file-block-store.cmake30
-rw-r--r--deployments/fwu/infra/semihosted-block-store.cmake39
-rw-r--r--deployments/internal-trusted-storage/config/default-opteesp/CMakeLists.txt88
-rw-r--r--deployments/internal-trusted-storage/config/default-opteesp/default_internal-trusted-storage.dts.in (renamed from deployments/internal-trusted-storage/opteesp/default_internal-trusted-storage.dts.in)6
-rw-r--r--deployments/internal-trusted-storage/config/default-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/internal-trusted-storage/config/default-sp/CMakeLists.txt92
-rw-r--r--deployments/internal-trusted-storage/config/default-sp/default_internal-trusted-storage.dts.in26
-rw-r--r--deployments/internal-trusted-storage/config/shared-flash-opteesp/CMakeLists.txt81
-rw-r--r--deployments/internal-trusted-storage/config/shared-flash-opteesp/default_internal-trusted-storage.dts.in21
-rw-r--r--deployments/internal-trusted-storage/config/shared-flash-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/internal-trusted-storage/env/commonsp/its_sp.c104
-rw-r--r--deployments/internal-trusted-storage/env/commonsp/its_sp.cmake31
-rw-r--r--deployments/internal-trusted-storage/env/commonsp/its_sp.h11
-rw-r--r--deployments/internal-trusted-storage/infra/sfs-ram.cmake23
-rw-r--r--deployments/internal-trusted-storage/infra/sfs-shared-flash.cmake34
-rw-r--r--deployments/internal-trusted-storage/internal-trusted-storage.cmake23
-rw-r--r--deployments/internal-trusted-storage/opteesp/.gitignore1
-rw-r--r--deployments/internal-trusted-storage/opteesp/CMakeLists.txt102
-rw-r--r--deployments/internal-trusted-storage/opteesp/sp.c66
-rw-r--r--deployments/internal-trusted-storage/opteesp/sp.h19
-rw-r--r--deployments/libsp/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/libsp/opteesp/CMakeLists.txt59
-rw-r--r--deployments/libsp/opteesp/LibspConfig.cmake.in9
-rw-r--r--deployments/libsp/opteesp/version.txt2
-rw-r--r--deployments/libts/arm-linux/CMakeLists.txt11
-rw-r--r--deployments/libts/libts-import.cmake94
-rw-r--r--deployments/libts/libts.cmake23
-rw-r--r--deployments/libts/libtsConfig.cmake.in10
-rw-r--r--deployments/libts/linux-pc/CMakeLists.txt104
-rw-r--r--deployments/libts/version.txt2
-rw-r--r--deployments/newlib/opteesp/CMakeLists.txt31
-rw-r--r--deployments/platform-inspect/arm-linux/CMakeLists.txt13
-rw-r--r--deployments/platform-inspect/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/platform-inspect/platform-inspect.cmake24
-rw-r--r--deployments/protected-storage/config/default-opteesp/CMakeLists.txt87
-rw-r--r--deployments/protected-storage/config/default-opteesp/default_protected-storage.dts.in (renamed from deployments/protected-storage/opteesp/default_protected-storage.dts.in)6
-rw-r--r--deployments/protected-storage/config/default-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/protected-storage/config/default-sp/CMakeLists.txt92
-rw-r--r--deployments/protected-storage/config/default-sp/default_protected-storage.dts.in26
-rw-r--r--deployments/protected-storage/config/shared-flash-opteesp/CMakeLists.txt79
-rw-r--r--deployments/protected-storage/config/shared-flash-opteesp/default_protected-storage.dts.in21
-rw-r--r--deployments/protected-storage/config/shared-flash-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/protected-storage/env/commonsp/ps_sp.c104
-rw-r--r--deployments/protected-storage/env/commonsp/ps_sp.cmake31
-rw-r--r--deployments/protected-storage/env/commonsp/ps_sp.h10
-rw-r--r--deployments/protected-storage/infra/sfs-ram.cmake23
-rw-r--r--deployments/protected-storage/infra/sfs-shared-flash.cmake34
-rw-r--r--deployments/protected-storage/opteesp/CMakeLists.txt104
-rw-r--r--deployments/protected-storage/opteesp/optee_sp_user_defines.h21
-rw-r--r--deployments/protected-storage/opteesp/sp.c66
-rw-r--r--deployments/protected-storage/opteesp/sp.h19
-rw-r--r--deployments/protected-storage/protected-storage.cmake23
-rw-r--r--deployments/psa-api-test/arch_test_runner.c134
-rw-r--r--deployments/psa-api-test/crypto/arm-linux/CMakeLists.txt4
-rw-r--r--deployments/psa-api-test/crypto/crypto_locator.c49
-rw-r--r--deployments/psa-api-test/crypto/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/psa-api-test/initial_attestation/arm-linux/CMakeLists.txt4
-rw-r--r--deployments/psa-api-test/initial_attestation/iat-api-test.cmake15
-rw-r--r--deployments/psa-api-test/initial_attestation/iat_locator.c51
-rw-r--r--deployments/psa-api-test/initial_attestation/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/psa-api-test/internal_trusted_storage/arm-linux/CMakeLists.txt4
-rw-r--r--deployments/psa-api-test/internal_trusted_storage/its-api-test.cmake4
-rw-r--r--deployments/psa-api-test/internal_trusted_storage/its_locator.c36
-rw-r--r--deployments/psa-api-test/internal_trusted_storage/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/psa-api-test/protected_storage/arm-linux/CMakeLists.txt4
-rw-r--r--deployments/psa-api-test/protected_storage/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/psa-api-test/protected_storage/ps-api-test.cmake4
-rw-r--r--deployments/psa-api-test/protected_storage/ps_locator.c38
-rw-r--r--deployments/psa-api-test/psa-api-test.cmake11
-rw-r--r--deployments/psa-api-test/service_under_test.h6
-rw-r--r--deployments/se-proxy/config/corstone1000-opteesp/CMakeLists.txt91
-rw-r--r--deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in43
-rw-r--r--deployments/se-proxy/config/corstone1000-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/se-proxy/config/default-opteesp/CMakeLists.txt93
-rw-r--r--deployments/se-proxy/config/default-opteesp/default_se-proxy.dts.in (renamed from deployments/se-proxy/opteesp/default_se-proxy.dts.in)6
-rw-r--r--deployments/se-proxy/config/default-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/se-proxy/config/default-sp/CMakeLists.txt92
-rw-r--r--deployments/se-proxy/config/default-sp/default_se-proxy.dts.in26
-rw-r--r--deployments/se-proxy/env/commonsp/se_proxy_sp.c148
-rw-r--r--deployments/se-proxy/env/commonsp/se_proxy_sp.cmake29
-rw-r--r--deployments/se-proxy/env/commonsp/se_proxy_sp.h10
-rw-r--r--deployments/se-proxy/infra/corstone1000/infra.cmake34
-rw-r--r--deployments/se-proxy/infra/corstone1000/service_proxy_factory.c131
-rw-r--r--deployments/se-proxy/infra/service_proxy_factory.h (renamed from deployments/se-proxy/opteesp/service_proxy_factory.h)10
-rw-r--r--deployments/se-proxy/infra/stub/service_proxy_factory.c69
-rw-r--r--deployments/se-proxy/infra/stub/stub.cmake29
-rw-r--r--deployments/se-proxy/opteesp/CMakeLists.txt166
-rw-r--r--deployments/se-proxy/opteesp/optee_sp_user_defines.h22
-rw-r--r--deployments/se-proxy/opteesp/se_proxy_sp.c94
-rw-r--r--deployments/se-proxy/opteesp/se_proxy_sp.h18
-rw-r--r--deployments/se-proxy/opteesp/service_proxy_factory.c66
-rw-r--r--deployments/se-proxy/se-proxy.cmake59
-rw-r--r--deployments/sfs-demo/opteesp/.gitignore1
-rw-r--r--deployments/sfs-demo/opteesp/CMakeLists.txt93
-rw-r--r--deployments/sfs-demo/opteesp/optee_sp_user_defines.h21
-rw-r--r--deployments/sfs-demo/opteesp/sp.c194
-rw-r--r--deployments/sfs-demo/opteesp/sp.h18
-rw-r--r--deployments/smm-gateway/common/smm_gateway.c139
-rw-r--r--deployments/smm-gateway/common/smm_gateway.h (renamed from deployments/smm-gateway/smm_gateway.h)5
-rw-r--r--deployments/smm-gateway/config/default-opteesp/CMakeLists.txt113
-rw-r--r--deployments/smm-gateway/config/default-opteesp/default_smm-gateway.dts.in (renamed from deployments/smm-gateway/opteesp/default_smm-gateway.dts.in)6
-rw-r--r--deployments/smm-gateway/config/default-opteesp/optee_sp_user_defines.h14
-rw-r--r--deployments/smm-gateway/config/default-sp/CMakeLists.txt112
-rw-r--r--deployments/smm-gateway/config/default-sp/default_smm-gateway.dts.in32
-rw-r--r--deployments/smm-gateway/config/linux-pc/CMakeLists.txt (renamed from deployments/smm-gateway/linux-pc/CMakeLists.txt)8
-rw-r--r--deployments/smm-gateway/env/commonsp/smm_gateway_sp.c148
-rw-r--r--deployments/smm-gateway/env/commonsp/smm_gateway_sp.cmake35
-rw-r--r--deployments/smm-gateway/env/commonsp/smm_gateway_sp.h10
-rw-r--r--deployments/smm-gateway/infra/psa-varstore.cmake23
-rw-r--r--deployments/smm-gateway/opteesp/CMakeLists.txt136
-rw-r--r--deployments/smm-gateway/opteesp/optee_sp_user_defines.h22
-rw-r--r--deployments/smm-gateway/opteesp/smm_gateway_sp.c108
-rw-r--r--deployments/smm-gateway/opteesp/smm_gateway_sp.h18
-rw-r--r--deployments/smm-gateway/smm-gateway.cmake61
-rw-r--r--deployments/smm-gateway/smm_gateway.c81
-rw-r--r--deployments/spm-test1/opteesp/CMakeLists.txt38
-rw-r--r--deployments/spm-test1/opteesp/default_spm_test1.dts.in33
-rw-r--r--deployments/spm-test2/opteesp/CMakeLists.txt38
-rw-r--r--deployments/spm-test2/opteesp/default_spm_test2.dts.in23
-rw-r--r--deployments/spm-test3/opteesp/CMakeLists.txt38
-rw-r--r--deployments/spm-test3/opteesp/default_spm_test3.dts.in23
-rw-r--r--deployments/spm-test4/opteesp/CMakeLists.txt38
-rw-r--r--deployments/spm-test4/opteesp/default_spm_test4.dts.in23
-rw-r--r--deployments/ts-demo/arm-linux/CMakeLists.txt5
-rw-r--r--deployments/ts-demo/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/ts-demo/ts-demo.cmake15
-rw-r--r--deployments/ts-demo/ts-demo.cpp16
-rw-r--r--deployments/ts-fw-test/linux-pc/CMakeLists.txt87
-rw-r--r--deployments/ts-fw-test/ts-fw-test.cmake63
-rw-r--r--deployments/ts-remote-test/arm-linux/CMakeLists.txt5
-rw-r--r--deployments/ts-remote-test/linux-pc/CMakeLists.txt4
-rw-r--r--deployments/ts-remote-test/ts-remote-test.cmake10
-rw-r--r--deployments/ts-remote-test/ts-remote-test.cpp13
-rw-r--r--deployments/ts-service-test/arm-linux/CMakeLists.txt9
-rw-r--r--deployments/ts-service-test/linux-pc/CMakeLists.txt45
-rw-r--r--deployments/ts-service-test/ts-service-test.cmake25
-rw-r--r--deployments/uefi-test/arm-linux/CMakeLists.txt42
-rw-r--r--deployments/uefi-test/linux-pc/CMakeLists.txt76
-rw-r--r--deployments/uefi-test/uefi-test.cmake53
-rw-r--r--docs/_static/css/custom.css18
-rw-r--r--docs/_static/images/tfm-contribution.pngbin0 -> 20538 bytes
-rw-r--r--docs/_static/images/tfm-documentation.pngbin0 -> 16947 bytes
-rw-r--r--docs/_static/images/tfm-integration.pngbin0 -> 22680 bytes
-rw-r--r--docs/_static/images/tfm-introduction.pngbin0 -> 20414 bytes
-rw-r--r--docs/_static/images/tfm-platform.pngbin0 -> 21364 bytes
-rw-r--r--docs/_static/images/tfm-reference.pngbin0 -> 20717 bytes
-rw-r--r--docs/_static/images/tfm-release.pngbin0 -> 26566 bytes
-rw-r--r--docs/certification/index.rst27
-rw-r--r--docs/certification/psa-certified.rst77
-rw-r--r--docs/certification/system-ready.rst27
-rw-r--r--docs/conf.py10
-rw-r--r--docs/deployments/index.rst31
-rw-r--r--docs/deployments/libraries.rst55
-rw-r--r--docs/deployments/secure-partitions.rst139
-rw-r--r--docs/deployments/test-executables.rst113
-rw-r--r--docs/deployments/tools-demo-apps.rst41
-rw-r--r--docs/developer/arch-overview.rst4
-rw-r--r--docs/developer/build-instructions.rst41
-rw-r--r--docs/developer/deployments.rst49
-rw-r--r--docs/developer/image/TSProtocolLayers.svg3
-rw-r--r--docs/developer/image/TSServiceDiscovery.svg3
-rw-r--r--docs/developer/image/TSportabilityModel.svg3
-rw-r--r--docs/developer/index.rst11
-rw-r--r--docs/developer/portability-model.rst211
-rw-r--r--docs/developer/project-structure.rst29
-rw-r--r--docs/developer/service-access-protocols.rst278
-rw-r--r--docs/developer/service-deployment-model.rst292
-rw-r--r--docs/developer/software-requirements.rst9
-rw-r--r--docs/developer/spmc-tests.rst180
-rw-r--r--docs/developer/uml/ServiceDeploymentDependencies.puml25
-rw-r--r--docs/developer/uml/SpmcTestStructure.puml34
-rw-r--r--docs/developer/uml/TSRPCCall.puml107
-rw-r--r--docs/developer/writing-documentation.rst7
-rw-r--r--docs/environments/deployment-guides/fvp-deployment-guide.rst86
-rw-r--r--docs/environments/deployment-guides/opteesp-deployment-guide.rst97
-rw-r--r--docs/environments/index.rst18
-rw-r--r--docs/environments/secure-partitions/ff-a/index.rst18
-rw-r--r--docs/environments/secure-partitions/index.rst40
-rw-r--r--docs/environments/secure-partitions/libsp.rst (renamed from docs/environments/ffa/libsp.rst)0
-rw-r--r--docs/environments/secure-partitions/spm/hafnium/index.rst19
-rw-r--r--docs/environments/secure-partitions/spm/optee/index.rst15
-rw-r--r--docs/environments/secure-partitions/spm/optee/opteesp-deployment-guide.rst91
-rw-r--r--docs/environments/secure-partitions/spm/optee/userspace-programs-on-fvp.rst150
-rw-r--r--docs/global_substitutions.txt7
-rw-r--r--docs/index.rst53
-rw-r--r--docs/overview/example-usage.rst (renamed from docs/overview/introduction.rst)36
-rw-r--r--docs/overview/image/TsReferencePlatform.svg4
-rw-r--r--docs/overview/index.rst45
-rw-r--r--docs/project/change-log.rst163
-rw-r--r--docs/project/coding-guidelines.rst52
-rw-r--r--docs/project/contributing.rst19
-rw-r--r--docs/project/glossary.rst69
-rw-r--r--docs/project/index.rst8
-rw-r--r--docs/project/quality-assurance/index.rst30
-rw-r--r--docs/project/quality-assurance/verification-methodology.rst71
-rw-r--r--docs/project/quality-assurance/verification-plan.rst37
-rw-r--r--docs/project/quality-assurance/verification-strategy.rst98
-rw-r--r--docs/project/releases.rst56
-rw-r--r--docs/project/todo.rst22
-rw-r--r--docs/project/version_control.rst68
-rw-r--r--docs/project/versioning_policy.rst29
-rw-r--r--docs/quickstart/index.rst18
-rw-r--r--docs/quickstart/optee-testing.rst92
-rw-r--r--docs/quickstart/pc-testing.rst78
-rw-r--r--docs/requirements.txt12
-rw-r--r--docs/security/generic-data-flow.graphml500
-rw-r--r--docs/security/generic-data-flow.svg252
-rw-r--r--docs/security/index.rst11
-rw-r--r--docs/security/threat-model.rst439
-rw-r--r--docs/services/attest-service-description.rst (renamed from docs/developer/service-descriptions/attest-service-description.rst)10
-rw-r--r--docs/services/block-storage-service-description.rst262
-rw-r--r--docs/services/crypto-service-description.rst (renamed from docs/developer/service-descriptions/crypto-service-description.rst)10
-rw-r--r--docs/services/fwu/fwu-gpt-disk-image.rst6
-rw-r--r--docs/services/fwu/fwu-service-description.rst565
-rw-r--r--docs/services/fwu/index.rst15
-rw-r--r--docs/services/image/block-storage-example-usage.svg4
-rw-r--r--docs/services/image/block-storage-layers.svg4
-rw-r--r--docs/services/image/fwu-reference-integration.svg4
-rw-r--r--docs/services/image/gpt-based-flash-layout.svg4
-rw-r--r--docs/services/image/smm-gateway-layers.svg4
-rw-r--r--docs/services/image/uefi-variable-structure.svg4
-rw-r--r--docs/services/image/update-agent-components.svg4
-rw-r--r--docs/services/index.rst (renamed from docs/developer/service-descriptions/index.rst)9
-rw-r--r--docs/services/secure-storage-service-description.rst (renamed from docs/developer/service-descriptions/secure-storage-service-description.rst)12
-rw-r--r--docs/services/uefi-smm-services.rst431
-rw-r--r--docs/services/uml/AttestClaimsModel.puml (renamed from docs/developer/service-descriptions/uml/AttestClaimsModel.puml)2
-rw-r--r--docs/services/uml/AttestImportedIAKflow.puml (renamed from docs/developer/service-descriptions/uml/AttestImportedIAKflow.puml)2
-rw-r--r--docs/services/uml/AttestPartitioning.puml (renamed from docs/developer/service-descriptions/uml/AttestPartitioning.puml)2
-rw-r--r--docs/services/uml/AttestSelfGeneratedIAKflow.puml (renamed from docs/developer/service-descriptions/uml/AttestSelfGeneratedIAKflow.puml)2
-rw-r--r--docs/services/uml/BlockStorageProvider.puml45
-rw-r--r--docs/services/uml/CryptoProviderClassDiagram.puml (renamed from docs/developer/service-descriptions/uml/CryptoProviderClassDiagram.puml)4
-rw-r--r--docs/services/uml/FwStoreClassDiagram.puml104
-rw-r--r--docs/services/uml/InternalTrustedDeploymentDiagram.puml (renamed from docs/developer/service-descriptions/uml/InternalTrustedDeploymentDiagram.puml)4
-rw-r--r--docs/services/uml/ProtectedProxyDeploymentDiagram.puml (renamed from docs/developer/service-descriptions/uml/ProtectedProxyDeploymentDiagram.puml)4
-rw-r--r--docs/services/uml/SecureStorageClassDiagram.puml (renamed from docs/developer/service-descriptions/uml/SecureStorageClassDiagram.puml)4
-rw-r--r--docs/services/uml/SmmGatewayOverview.puml14
-rw-r--r--docs/services/uml/UpdateAgentClassDiagram.puml100
-rw-r--r--docs/standards/ff-a.rst20
-rw-r--r--docs/standards/index.rst15
-rw-r--r--docs/standards/psa.rst21
-rw-r--r--docs/target-platforms/aem-fvp.rst20
-rw-r--r--docs/target-platforms/index.rst39
-rw-r--r--environments/arm-linux/default_toolchain_file.cmake45
-rw-r--r--environments/linux-pc/component.cmake25
-rw-r--r--environments/linux-pc/default_toolchain_file.cmake42
-rw-r--r--environments/linux-pc/posix_trace.c17
-rw-r--r--environments/opteesp/ExportSp.cmake46
-rw-r--r--environments/opteesp/component.cmake47
-rw-r--r--environments/opteesp/default_toolchain_file.cmake57
-rw-r--r--environments/opteesp/include/libc_init.h11
-rw-r--r--environments/opteesp/include/optee_sp_internal_api.h3
-rw-r--r--environments/opteesp/include/stdarg.h20
-rw-r--r--environments/opteesp/include/stdbool.h17
-rw-r--r--environments/opteesp/include/stddef.h27
-rw-r--r--environments/opteesp/include/stddef_.h15
-rw-r--r--environments/opteesp/sp.ld.S6
-rw-r--r--environments/opteesp/sp_assert.c (renamed from environments/opteesp/newlib_sp_assert.c)7
-rw-r--r--environments/opteesp/sp_entry.c2
-rw-r--r--environments/opteesp/sp_pkg.json.in7
-rw-r--r--environments/opteesp/sp_trace.c11
-rw-r--r--environments/sp/component.cmake51
-rw-r--r--environments/sp/default_toolchain_file.cmake58
-rw-r--r--environments/sp/entry.S85
-rw-r--r--environments/sp/env.cmake23
-rw-r--r--environments/sp/newlib_init.c20
-rw-r--r--environments/sp/sp.ld.S111
-rw-r--r--environments/sp/sp_assert.c22
-rw-r--r--environments/sp/sp_entry.c30
-rw-r--r--environments/sp/sp_pkg.json.in7
-rw-r--r--environments/sp/sp_trace.c23
-rw-r--r--external/CppUTest/CppUTest.cmake94
-rw-r--r--external/CppUTest/cpputest-init-cache.cmake.in21
-rw-r--r--external/LinuxFFAUserShim/LinuxFFAUserShim.cmake88
-rw-r--r--external/LinuxFfaTeeDriver/LinuxFfaTeeDriver.cmake54
-rw-r--r--external/MbedTLS/0001-Add-capability-to-selectively-build-libraries.patch144
-rw-r--r--external/MbedTLS/MbedTLS.cmake131
-rw-r--r--external/MbedTLS/config/crypto_posix.h (renamed from components/service/crypto/client/cpp/config_mbedtls_user.h)15
-rw-r--r--external/MbedTLS/config/libmbed_only.h25
-rw-r--r--external/MbedTLS/config/libmbedx509.h38
-rw-r--r--external/MbedTLS/config/x509_only.h32
-rw-r--r--external/MbedTLS/mbedtls-init-cache.cmake.in24
-rw-r--r--external/Spdevkit/FindSpdevkit.cmake179
-rw-r--r--external/edk2_platforms/morello.cmake28
-rw-r--r--external/firmware_test_builder/FirmwareTestBuilder.cmake28
-rw-r--r--external/libfdt/fix-strnlen.patch30
-rw-r--r--external/libfdt/libfdt.cmake57
-rw-r--r--external/nanopb/nanopb-init-cache.cmake.in22
-rw-r--r--external/nanopb/nanopb.cmake145
-rw-r--r--external/nanopb/requirements.txt4
-rw-r--r--external/newlib/0001-Allow-aarch64-linux-gcc-to-compile-bare-metal-lib.patch19
-rw-r--r--external/newlib/0002-Disable-unnecessary-targets.patch31
-rw-r--r--external/newlib/newlib.cmake326
-rw-r--r--external/newlib/newlib_init.c (renamed from environments/opteesp/newlib_init.c)0
-rw-r--r--external/newlib/newlib_sp_assert.c21
-rw-r--r--external/newlib/newlib_sp_heap.c (renamed from environments/opteesp/newlib_sp_heap.c)9
-rw-r--r--external/openamp/libmetal-init-cache.cmake.in20
-rw-r--r--external/openamp/libmetal.cmake69
-rw-r--r--external/openamp/openamp-init-cache.cmake.in20
-rw-r--r--external/openamp/openamp.cmake69
-rw-r--r--external/psa_arch_tests/modify_attest_config.patch13
-rw-r--r--external/psa_arch_tests/psa-arch-test-init-cache.cmake.in26
-rw-r--r--external/psa_arch_tests/psa_arch_tests.cmake89
-rw-r--r--external/qcbor/0001-Add-3rd-party-settings.patch28
-rw-r--r--external/qcbor/0001-Introduce-a-way-to-allow-setting-macro-definitions-e.patch35
-rw-r--r--external/qcbor/0002-Add-install-definition.patch14
-rw-r--r--external/qcbor/0003-Fix-stop-overriding-C_FLAGS-from-environment.patch31
-rw-r--r--external/qcbor/qcbor-init-cache.cmake.in17
-rw-r--r--external/qcbor/qcbor.cmake101
-rw-r--r--external/t_cose/0002-Fix-stop-overriding-C_FLAGS-from-environment.patch31
-rw-r--r--external/t_cose/0002-add-tls3_0_0-compatibility.patch31
-rw-r--r--external/t_cose/t_cose-init-cache.cmake.in13
-rw-r--r--external/t_cose/t_cose.cmake113
-rw-r--r--external/tf_a/include/cdefs.h16
-rw-r--r--external/tf_a/include/common/debug.h30
-rw-r--r--external/tf_a/include/lib/utils.h30
-rw-r--r--external/tf_a/include/plat/common/platform.h29
-rw-r--r--external/tf_a/include/platform_def.h29
-rw-r--r--external/tf_a/tf-a.cmake62
-rw-r--r--platform/drivers/arm/juno_trng/juno_trng_adapter.c24
-rw-r--r--platform/drivers/arm/mhu_driver/component.cmake (renamed from components/service/discovery/provider/component.cmake)11
-rw-r--r--platform/drivers/arm/mhu_driver/mhu_v2.h391
-rw-r--r--platform/drivers/arm/mhu_driver/mhu_v2_x.c602
-rw-r--r--platform/drivers/arm/tztrng/driver.cmake4
-rw-r--r--platform/drivers/arm/tztrng/tztrng_adapter.c35
-rw-r--r--platform/drivers/edk2-platforms/Platform/ARM/Morello/Drivers/CadenceQspiDxe.cmake15
-rw-r--r--platform/drivers/mock/mock_trng.c8
-rw-r--r--platform/drivers/tf-a/drivers/cfi/v2m/v2m_flash.cmake13
-rw-r--r--platform/drivers/tf-a/lib/semihosting/driver.cmake20
-rw-r--r--platform/interface/trng.h7
-rw-r--r--platform/providers/arm/corstone1000/platform.cmake15
-rw-r--r--platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake12
-rw-r--r--platform/providers/arm/n1sdp/platform.cmake16
-rw-r--r--protocols/common/efi/efi_certificate.h52
-rw-r--r--protocols/common/efi/efi_global_variable.h181
-rw-r--r--protocols/common/efi/efi_image_authentication.h274
-rw-r--r--protocols/common/efi/efi_types.h19
-rw-r--r--protocols/common/osf/uuid.h23
-rw-r--r--protocols/service/block_storage/packed-c/messages.h129
-rw-r--r--protocols/service/block_storage/packed-c/opcodes.h22
-rw-r--r--protocols/service/crypto/packed-c/opcodes.h5
-rw-r--r--protocols/service/crypto/packed-c/verify_pkcs7_signature.h18
-rw-r--r--protocols/service/crypto/protobuf/opcodes.proto4
-rw-r--r--protocols/service/fwu/packed-c/fwu_proto.h112
-rw-r--r--protocols/service/fwu/packed-c/metadata.h22
-rw-r--r--protocols/service/fwu/packed-c/metadata_v1.h82
-rw-r--r--protocols/service/fwu/packed-c/metadata_v2.h107
-rw-r--r--protocols/service/fwu/packed-c/opcodes.h24
-rw-r--r--protocols/service/fwu/packed-c/status.h23
-rw-r--r--protocols/service/rpmb/packed-c/rpmb_proto.h41
-rw-r--r--protocols/service/smm_variable/parameters.h36
-rw-r--r--protocols/service/smm_variable/smm_variable_proto.h2
-rw-r--r--protocols/test_api/fw-test-api.yaml94
-rw-r--r--requirements.txt8
-rw-r--r--tools/b-test/Makefile38
-rw-r--r--tools/b-test/requirements.txt4
-rw-r--r--tools/b-test/run.sh.j2338
-rw-r--r--tools/b-test/test_data.yaml210
-rwxr-xr-xtools/bash/uefi_authenticated_variables/generate_auth_headers.sh153
-rw-r--r--tools/cmake/common/AddComponents.cmake16
-rw-r--r--tools/cmake/common/AddPlatform.cmake20
-rw-r--r--tools/cmake/common/ExportLibrary.cmake79
-rw-r--r--tools/cmake/common/ExportMemoryRegionsToManifest.cmake46
-rw-r--r--tools/cmake/common/ExportSp.cmake117
-rw-r--r--tools/cmake/common/LazyFetch.cmake316
-rw-r--r--tools/cmake/common/PropertyCopy.cmake459
-rw-r--r--tools/cmake/common/TargetCompileDefinitions.cmake65
-rw-r--r--tools/cmake/common/Utils.cmake57
-rw-r--r--tools/cmake/common/Uuid.cmake166
-rw-r--r--tools/cmake/compiler/GCC.cmake281
-rw-r--r--tools/python/elf_segments_to_manifest.py187
-rw-r--r--tools/python/merge_json.py55
-rw-r--r--tools/python/requirements.txt7
-rw-r--r--version.txt2
1226 files changed, 88575 insertions, 17774 deletions
diff --git a/.checkpatch b/.checkpatch
new file mode 100644
index 000000000..dd8dad99a
--- /dev/null
+++ b/.checkpatch
@@ -0,0 +1,14 @@
+# Copyright (c) 2021-2023, Arm Limited and contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Checkpatch configuration for Trusted Services.
+
+--showfile
+--codespell
+--ignore SPDX_LICENSE_TAG,PREFER_KERNEL_TYPES,USLEEP_RANGE,GERRIT_CHANGE_ID,FILE_PATH_CHANGES,UNNECESSARY_PARENTHESES,PREFER_DEFINED_ATTRIBUTE_MACRO,BIT_MACRO
+--no-tree
+--terse
+--strict
+--max-line-length=100
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000..b1822f92d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,130 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+---
+AccessModifierOffset: -8
+AlignAfterOpenBracket: Align
+AlignConsecutiveMacros: true
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Left
+AlignOperands: true
+AlignTrailingComments: false
+AllowAllArgumentsOnNextLine: false
+AllowAllConstructorInitializersOnNextLine: false
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ AfterExternBlock: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+ BeforeLambdaBody: false
+ BeforeWhile: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeComma
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializers: BeforeComma
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+ColumnLimit: 100
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+Cpp11BracedListStyle: false
+DeriveLineEnding: false
+DerivePointerAlignment: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^<.+>$'
+ Priority: 1
+ - Regex: '^".+"$'
+ Priority: 2
+ - Regex: '.*'
+ Priority: 0
+IncludeIsMainRegex: (Test)?$
+IncludeIsMainSourceRegex: ''
+IndentCaseLabels: false
+IndentPPDirectives: None
+IndentWidth: 8
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 8
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 10
+PenaltyBreakBeforeFirstCallParameter: 30
+PenaltyBreakComment: 10
+PenaltyBreakFirstLessLess: 0
+PenaltyBreakString: 10
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 100
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+ReflowComments: false
+
+SortIncludes: true
+SortUsingDeclarations: false
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp03
+TabWidth: 8
+UseCRLF: false
+UseTab: Always
+
diff --git a/.cppcheck b/.cppcheck
new file mode 100644
index 000000000..ab5af7d94
--- /dev/null
+++ b/.cppcheck
@@ -0,0 +1,22 @@
+
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+# cppcheck options to check the whole repo. This is a limited approach as
+# deployment specific settings can not be used (include paths, macro definitions
+# platform, etc...).
+# use this file as:
+# cppcheck $(sed "s/#.*//g" ".cppcheck") .
+--enable=all --suppress=missingInclude -q --std=c99
+--platform=unix64
+# Output in checkpatch compatible format.
+--template={file}:{line}:{severity}:{id},{message}
+-I components/common/utils/include
+-I components/messaging/ffa/libsp/include
+-I components/rpc/common/interface
+-I components/service/locator/interface
+-I components/messaging/ffa/libsp/include
+-I components/common/utils/include
diff --git a/.gitignore b/.gitignore
index c6179770a..6d6a83f02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -24,3 +24,5 @@
**/.project
**/.pydevproject
**/.settings/
+tools/bash/uefi_authenticated_variables/temp_files/
+tools/bash/uefi_authenticated_variables/auth_vectors/
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 000000000..a33d90cfb
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,23 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the version of tools you might need
+build:
+ os: ubuntu-20.04
+ tools:
+ python: "3.8"
+ apt_packages:
+ - plantuml
+
+# Build documentation in the docs/ directory with Sphinx
+sphinx:
+ configuration: docs/conf.py
+
+# Optionally declare the Python requirements required to build your docs
+python:
+ install:
+ - requirements: docs/requirements.txt \ No newline at end of file
diff --git a/components/app/fwu-tool/app/fwu_app.cpp b/components/app/fwu-tool/app/fwu_app.cpp
new file mode 100644
index 000000000..173afce1e
--- /dev/null
+++ b/components/app/fwu-tool/app/fwu_app.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fwu_app.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <errno.h>
+
+#include "media/volume/factory/volume_factory.h"
+#include "metadata_reader.h"
+#include "service/block_storage/factory/file/block_store_factory.h"
+#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/config/fwu_configure.h"
+#include "service/fwu/fw_store/banked/bank_scheme.h"
+#include "service/fwu/fw_store/banked/banked_fw_store.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h"
+#include "service/fwu/inspector/direct/direct_fw_inspector.h"
+#include "service/fwu/installer/factory/installer_factory.h"
+
+extern "C" {
+#include "trace.h"
+}
+
+fwu_app::fwu_app()
+ : m_update_agent()
+ , m_fw_store()
+{
+ memset(&m_update_agent, 0, sizeof(m_update_agent));
+ memset(&m_fw_store, 0, sizeof(m_fw_store));
+}
+
+fwu_app::~fwu_app()
+{
+ update_agent_deinit(&m_update_agent);
+ banked_fw_store_deinit(&m_fw_store);
+
+ fwu_deconfigure();
+ volume_factory_deinit();
+}
+
+int fwu_app::configure(const char *disk_img_filename)
+{
+ if (disk_img_filename)
+ file_block_store_factory_set_filename(disk_img_filename);
+
+ struct uuid_octets device_uuids[MAX_STORAGE_DEVICES];
+ size_t num_storage_devices = 0;
+
+ int status = volume_factory_init(device_uuids, MAX_STORAGE_DEVICES, &num_storage_devices);
+
+ if (status) {
+ EMSG("Failed to init volume factory: %d", status);
+ return -EIO;
+ }
+
+ status = fwu_configure(device_uuids, num_storage_devices);
+
+ if (status) {
+ EMSG("Failed to setup FWU configuration: %d", status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int fwu_app::get_boot_info(unsigned int &active_index, unsigned int &metadata_version)
+{
+ return metadata_reader::instance()->get_boot_info(active_index, metadata_version);
+}
+
+int fwu_app::init_update_agent(unsigned int boot_index, unsigned int metadata_version)
+{
+ if (boot_index >= BANK_SCHEME_NUM_BANKS) {
+ IMSG("Invalid boot index");
+ return -1;
+ }
+
+ const struct metadata_serializer *serializer = select_metadata_serializer(metadata_version);
+
+ if (!serializer) {
+ IMSG("Unsupported FWU metadata version");
+ return -1;
+ }
+
+ /* Initialise update_agent */
+ int status = banked_fw_store_init(&m_fw_store, serializer);
+
+ if (status) {
+ IMSG("fw store initialisation error %d", status);
+ return -1;
+ }
+
+ status = update_agent_init(&m_update_agent, boot_index, direct_fw_inspector_inspect,
+ &m_fw_store);
+
+ if (status) {
+ IMSG("update agent initialisation error %d", status);
+ return -1;
+ }
+
+ /* Success */
+ return 0;
+}
+
+int fwu_app::update_image(const struct uuid_octets &img_type_uuid, const uint8_t *img_data,
+ size_t img_size)
+{
+ int status = update_agent_begin_staging(&m_update_agent);
+
+ if (status)
+ return status;
+
+ uint32_t stream_handle = 0;
+
+ status = update_agent_open(&m_update_agent, &img_type_uuid, &stream_handle);
+
+ if (!status) {
+ status = update_agent_write_stream(&m_update_agent, stream_handle, img_data,
+ img_size);
+
+ if (!status)
+ status = update_agent_commit(&m_update_agent, stream_handle, false);
+ }
+
+ if (!status)
+ status = update_agent_end_staging(&m_update_agent);
+ else
+ update_agent_cancel_staging(&m_update_agent);
+
+ return status;
+}
+
+int fwu_app::read_object(const struct uuid_octets &object_uuid, std::vector<uint8_t> &data)
+{
+ uint32_t stream_handle = 0;
+ int status = update_agent_open(&m_update_agent, &object_uuid, &stream_handle);
+
+ if (status)
+ return status;
+
+ /* Don't yet know how big the object will be so allocate some space to get
+ * started with the initial read.
+ */
+ size_t reported_total_len = 0;
+ size_t read_so_far = 0;
+ size_t vector_capacity = 512;
+
+ data.resize(vector_capacity);
+
+ do {
+ size_t data_len_read = 0;
+ size_t requested_read_len = vector_capacity - read_so_far;
+
+ status = update_agent_read_stream(&m_update_agent, stream_handle,
+ &data[read_so_far], requested_read_len,
+ &data_len_read, &reported_total_len);
+
+ read_so_far += data_len_read;
+ data.resize(read_so_far);
+
+ if (reported_total_len > vector_capacity) {
+ vector_capacity = reported_total_len;
+ data.resize(vector_capacity);
+ }
+
+ assert(read_so_far <= reported_total_len);
+
+ if (read_so_far == reported_total_len) {
+ /* Read all the data */
+ if (vector_capacity > reported_total_len)
+ data.resize(reported_total_len);
+
+ break;
+ }
+
+ } while (!status);
+
+ status = update_agent_commit(&m_update_agent, stream_handle, false);
+
+ return status;
+}
+
+struct update_agent *fwu_app::update_agent()
+{
+ return &m_update_agent;
+}
+
+const struct metadata_serializer *fwu_app::select_metadata_serializer(unsigned int version)
+{
+ if (version == 1)
+ return metadata_serializer_v1();
+
+ if (version == 2)
+ return metadata_serializer_v2();
+
+ return NULL;
+}
diff --git a/components/app/fwu-tool/app/fwu_app.h b/components/app/fwu-tool/app/fwu_app.h
new file mode 100644
index 000000000..8bbaa9d48
--- /dev/null
+++ b/components/app/fwu-tool/app/fwu_app.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_APP_H
+#define FWU_APP_H
+
+#include <stdint.h>
+#include <vector>
+
+#include "common/uuid/uuid.h"
+#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/fw_store/banked/banked_fw_store.h"
+
+/*
+ * The fwu_app class is intended to provide the core for an application
+ * that uses the update_agent for updating the contents of a disk image
+ * file. The app uses standard fwu components, such as the update_agent,
+ * to manage updates. To support additional update methods (e.g.
+ * update_capsule), inherit from this class and add additional methods
+ * to the derived class. This allows the core app to be reused for
+ * different application areas without overloading the base app.
+ */
+class fwu_app {
+public:
+ fwu_app();
+ virtual ~fwu_app();
+
+ /**
+ * \brief Configure storage and installers
+ *
+ * Configures a set of storage volumes and installers to manage the
+ * contents of the specified disk image file.
+ *
+ * \param[in] disk_img_filename UEFI formatted disk image
+ *
+ * \return Status (0 on success)
+ */
+ int configure(const char *disk_img_filename);
+
+ /**
+ * \brief Get boot info from the FWU metadata
+ *
+ * \param[out] active_index The active index seen by the bootloader
+ * \param[out] metadata_version Current metadata version
+ *
+ * \return Status (0 on success)
+ */
+ int get_boot_info(unsigned int &active_index, unsigned int &metadata_version);
+
+ /**
+ * \brief Initialise the update agent
+ *
+ * \param[in] boot_index The boot_index chosen by the bootloader
+ * \param[in] metadata_version Current metadata version
+ *
+ * \return Status (0 on success)
+ */
+ int init_update_agent(unsigned int boot_index, unsigned int metadata_version);
+
+ /**
+ * \brief Update a single image
+ *
+ * Begins staging, writes the raw contents of the image file and ends
+ * staging.
+ *
+ * \param[in] img_type_uuid UUID of image to update
+ * \param[in] img_data Buffer containing image data
+ * \param[in] img_size Size in bytes of image
+ *
+ * \return Status (0 on success)
+ */
+ int update_image(const struct uuid_octets &img_type_uuid, const uint8_t *img_data,
+ size_t img_size);
+
+ /**
+ * \brief Read an object from the update agent
+ *
+ * \param[in] object_uuid UUID of object
+ * \param[out] data Read object data
+ *
+ * \return Status (0 on success)
+ */
+ int read_object(const struct uuid_octets &object_uuid, std::vector<uint8_t> &data);
+
+protected:
+ /**
+ * \brief Return pointer to update_agent struct
+ *
+ * \return Pointer to the core update_agent.
+ */
+ struct update_agent *update_agent();
+
+private:
+ static const size_t MAX_STORAGE_DEVICES = 4;
+
+ static const struct metadata_serializer *select_metadata_serializer(unsigned int version);
+
+ struct update_agent m_update_agent;
+ struct fw_store m_fw_store;
+};
+
+#endif /* FWU_APP_H */
diff --git a/components/app/fwu-tool/app/metadata_reader.cpp b/components/app/fwu-tool/app/metadata_reader.cpp
new file mode 100644
index 000000000..2d38a2f39
--- /dev/null
+++ b/components/app/fwu-tool/app/metadata_reader.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "metadata_reader.h"
+
+#include "media/volume/index/volume_index.h"
+#include "media/volume/volume.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+
+extern "C" {
+#include "trace.h"
+}
+
+metadata_reader::metadata_reader()
+ : registered_readers()
+{
+}
+
+metadata_reader::~metadata_reader()
+{
+}
+
+metadata_reader *metadata_reader::instance()
+{
+ static metadata_reader the_instance;
+ return &the_instance;
+}
+
+void metadata_reader::register_reader(metadata_version_specific_reader *reader)
+{
+ registered_readers.push_back(reader);
+}
+
+int metadata_reader::get_boot_info(unsigned int &active_index, unsigned int &metadata_version) const
+{
+ struct volume *volume;
+
+ int status = volume_index_find(BANKED_VOLUME_ID_PRIMARY_METADATA, &volume);
+
+ if (status) {
+ IMSG("Failed to find metadata volume");
+ return status;
+ }
+
+ status = volume_open(volume);
+
+ if (!status) {
+ /* Assume whatever metadata version is in-use, it will fit in the buffer */
+ size_t len_read = 0;
+ uint8_t buf[1000];
+
+ status = volume_read(volume, (uintptr_t)buf, sizeof(buf), &len_read);
+
+ if (!status) {
+ bool is_handled = false;
+
+ for (unsigned int i = 0; i < registered_readers.size(); i++) {
+ metadata_version_specific_reader *reader = registered_readers[i];
+
+ if (reader->is_supported(buf, len_read)) {
+ reader->get_version(buf, len_read, metadata_version);
+ reader->get_active_index(buf, len_read, active_index);
+
+ is_handled = true;
+ break;
+ }
+ }
+
+ if (!is_handled) {
+ /* This is normal on first-boot */
+ status = -1;
+ }
+
+ } else
+ IMSG("Failed to read metadata volume");
+
+ volume_close(volume);
+
+ } else
+ IMSG("Failed to open metadata volume");
+
+ return status;
+}
diff --git a/components/app/fwu-tool/app/metadata_reader.h b/components/app/fwu-tool/app/metadata_reader.h
new file mode 100644
index 000000000..29a4d9b0a
--- /dev/null
+++ b/components/app/fwu-tool/app/metadata_reader.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_METADATA_READER_H
+#define FWU_METADATA_READER_H
+
+#include <cstdint>
+#include <cstddef>
+#include <vector>
+
+/*
+ * A version specific metadata reader. Before using get methods to extract
+ * metadata attributes, is_supported() should be called to verify that the
+ * input metadata version is supported.
+ */
+class metadata_version_specific_reader {
+public:
+ virtual ~metadata_version_specific_reader()
+ {
+ }
+
+ virtual bool is_supported(const uint8_t *buf, size_t data_len) const = 0;
+
+ virtual void get_version(const uint8_t *buf, size_t data_len,
+ unsigned int &version) const = 0;
+
+ virtual void get_active_index(const uint8_t *buf, size_t data_len,
+ unsigned int &active_index) const = 0;
+};
+
+/*
+ * A singleton that provides a common interface for reading fwu metadata.
+ * The caller doesn't need to worry about the version of metadata being used.
+ */
+class metadata_reader {
+public:
+ static metadata_reader *instance();
+ ~metadata_reader();
+
+ void register_reader(metadata_version_specific_reader *reader);
+
+ int get_boot_info(unsigned int &active_index, unsigned int &metadata_version) const;
+
+private:
+ metadata_reader();
+
+ std::vector<metadata_version_specific_reader *> registered_readers;
+};
+
+#endif /* FWU_METADATA_READER_H */
diff --git a/components/app/fwu-tool/app/metadata_v1_reader.cpp b/components/app/fwu-tool/app/metadata_v1_reader.cpp
new file mode 100644
index 000000000..195fa6ecc
--- /dev/null
+++ b/components/app/fwu-tool/app/metadata_v1_reader.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include "metadata_reader.h"
+#include "protocols/service/fwu/packed-c/metadata_v1.h"
+
+class metadata_v1_reader : public metadata_version_specific_reader {
+public:
+ metadata_v1_reader();
+ ~metadata_v1_reader();
+
+ bool is_supported(const uint8_t *buf, size_t data_len) const override;
+
+ void get_version(const uint8_t *buf, size_t data_len, unsigned int &version) const override;
+
+ void get_active_index(const uint8_t *buf, size_t data_len,
+ unsigned int &active_index) const override;
+};
+
+/* Registers on static construction */
+static metadata_v1_reader the_v1_reader;
+
+metadata_v1_reader::metadata_v1_reader()
+ : metadata_version_specific_reader()
+{
+ metadata_reader::instance()->register_reader(this);
+}
+
+metadata_v1_reader::~metadata_v1_reader()
+{
+}
+
+bool metadata_v1_reader::is_supported(const uint8_t *buf, size_t data_len) const
+{
+ assert(buf);
+
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)buf;
+
+ return (data_len >= sizeof(struct fwu_metadata)) && (metadata->version == 1);
+}
+
+void metadata_v1_reader::get_version(const uint8_t *buf, size_t data_len,
+ unsigned int &version) const
+{
+ assert(buf);
+ assert(data_len >= sizeof(struct fwu_metadata));
+
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)buf;
+
+ version = metadata->version;
+}
+
+void metadata_v1_reader::get_active_index(const uint8_t *buf, size_t data_len,
+ unsigned int &active_index) const
+{
+ assert(buf);
+ assert(data_len >= sizeof(struct fwu_metadata));
+
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)buf;
+
+ active_index = metadata->active_index;
+} \ No newline at end of file
diff --git a/components/app/fwu-tool/app/metadata_v2_reader.cpp b/components/app/fwu-tool/app/metadata_v2_reader.cpp
new file mode 100644
index 000000000..61faa61d1
--- /dev/null
+++ b/components/app/fwu-tool/app/metadata_v2_reader.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include "metadata_reader.h"
+#include "protocols/service/fwu/packed-c/metadata_v2.h"
+
+class metadata_v2_reader : public metadata_version_specific_reader {
+public:
+ metadata_v2_reader();
+ ~metadata_v2_reader();
+
+ bool is_supported(const uint8_t *buf, size_t data_len) const override;
+
+ void get_version(const uint8_t *buf, size_t data_len, unsigned int &version) const override;
+
+ void get_active_index(const uint8_t *buf, size_t data_len,
+ unsigned int &active_index) const override;
+};
+
+/* Registers on static construction */
+static metadata_v2_reader the_v2_reader;
+
+metadata_v2_reader::metadata_v2_reader()
+ : metadata_version_specific_reader()
+{
+ metadata_reader::instance()->register_reader(this);
+}
+
+metadata_v2_reader::~metadata_v2_reader()
+{
+}
+
+bool metadata_v2_reader::is_supported(const uint8_t *buf, size_t data_len) const
+{
+ assert(buf);
+
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)buf;
+
+ return (data_len >= sizeof(struct fwu_metadata)) && (metadata->version == 2);
+}
+
+void metadata_v2_reader::get_version(const uint8_t *buf, size_t data_len,
+ unsigned int &version) const
+{
+ assert(buf);
+ assert(data_len >= sizeof(struct fwu_metadata));
+
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)buf;
+
+ version = metadata->version;
+}
+
+void metadata_v2_reader::get_active_index(const uint8_t *buf, size_t data_len,
+ unsigned int &active_index) const
+{
+ assert(buf);
+ assert(data_len >= sizeof(struct fwu_metadata));
+
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)buf;
+
+ active_index = metadata->active_index;
+} \ No newline at end of file
diff --git a/components/app/fwu-tool/cmd_print_image_dir.cpp b/components/app/fwu-tool/cmd_print_image_dir.cpp
new file mode 100644
index 000000000..1e0702751
--- /dev/null
+++ b/components/app/fwu-tool/cmd_print_image_dir.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cmd_print_image_dir.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <vector>
+
+#include "common/uuid/uuid.h"
+#include "print_uuid.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+
+void cmd_print_image_dir(fwu_app &app)
+{
+ std::vector<uint8_t> fetched_object;
+ struct uuid_octets object_uuid;
+
+ uuid_guid_octets_from_canonical(&object_uuid, FWU_DIRECTORY_CANONICAL_UUID);
+
+ int status = app.read_object(object_uuid, fetched_object);
+
+ if (status) {
+ printf("Error: failed to read image directory\n");
+ return;
+ }
+
+ if (fetched_object.size() < offsetof(ts_fwu_image_directory, img_info_entry)) {
+ printf("Error: invalid image directory size\n");
+ return;
+ }
+
+ const struct ts_fwu_image_directory *img_dir =
+ (const struct ts_fwu_image_directory *)fetched_object.data();
+
+ printf("\nimage_directory (size %zu bytes) :\n", fetched_object.size());
+ printf("\tdirectory_version : %d\n", img_dir->directory_version);
+ printf("\tnum_images : %d\n", img_dir->num_images);
+ printf("\tcorrect_boot : %d\n", img_dir->correct_boot);
+
+ for (unsigned int i = 0; i < img_dir->num_images; i++) {
+ printf("\timg_info_entry[%u]:\n", i);
+ printf("\t\timg_type_uuid : %s\n",
+ print_uuid(img_dir->img_info_entry[i].img_type_uuid).c_str());
+ printf("\t\tclient_permissions : 0x%x\n",
+ img_dir->img_info_entry[i].client_permissions);
+ printf("\t\timg_max_size : %d\n", img_dir->img_info_entry[i].img_max_size);
+ printf("\t\tlowest_accepted_version : %d\n",
+ img_dir->img_info_entry[i].lowest_accepted_version);
+ printf("\t\timg_version : %d\n", img_dir->img_info_entry[i].img_version);
+ printf("\t\taccepted : %d\n", img_dir->img_info_entry[i].accepted);
+ }
+}
diff --git a/components/app/fwu-tool/cmd_print_image_dir.h b/components/app/fwu-tool/cmd_print_image_dir.h
new file mode 100644
index 000000000..6a8f91e81
--- /dev/null
+++ b/components/app/fwu-tool/cmd_print_image_dir.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CMD_PRINT_IMAGE_DIR_H
+#define CMD_PRINT_IMAGE_DIR_H
+
+#include "app/fwu_app.h"
+
+void cmd_print_image_dir(fwu_app &app);
+
+#endif /* CMD_PRINT_IMAGE_DIR_H */
diff --git a/components/app/fwu-tool/cmd_print_metadata_v1.cpp b/components/app/fwu-tool/cmd_print_metadata_v1.cpp
new file mode 100644
index 000000000..6539e5740
--- /dev/null
+++ b/components/app/fwu-tool/cmd_print_metadata_v1.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cmd_print_metadata_v1.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <vector>
+
+#include "common/uuid/uuid.h"
+#include "print_uuid.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+#include "protocols/service/fwu/packed-c/metadata_v1.h"
+
+void cmd_print_metadata_v1(fwu_app &app)
+{
+ std::vector<uint8_t> fetched_object;
+ struct uuid_octets object_uuid;
+
+ uuid_guid_octets_from_canonical(&object_uuid, FWU_METADATA_CANONICAL_UUID);
+
+ int status = app.read_object(object_uuid, fetched_object);
+
+ if (status) {
+ printf("Error: failed to read metadata\n");
+ return;
+ }
+
+ if (fetched_object.size() < sizeof(struct fwu_metadata)) {
+ printf("Error: invalid metadata size\n");
+ return;
+ }
+
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)fetched_object.data();
+
+ printf("\nfwu_metadata (size %zu bytes) :\n", fetched_object.size());
+ printf("\tcrc_32 : 0x%x\n", metadata->crc_32);
+ printf("\tversion : %d\n", metadata->version);
+ printf("\tactive_index : %d\n", metadata->active_index);
+ printf("\tprevious_active_index : %d\n", metadata->previous_active_index);
+
+ for (unsigned int i = 0; i < FWU_METADATA_NUM_IMAGE_ENTRIES; i++) {
+ printf("\timg_entry[%u]:\n", i);
+ printf("\t\timg_type_uuid : %s\n",
+ print_uuid(metadata->img_entry[i].img_type_uuid).c_str());
+ printf("\t\tlocation_uuid : %s\n",
+ print_uuid(metadata->img_entry[i].location_uuid).c_str());
+
+ for (unsigned int bank_index = 0; bank_index < FWU_METADATA_NUM_BANKS;
+ bank_index++) {
+ printf("\t\timg_props[%u]:\n", bank_index);
+ printf("\t\t\timg_uuid : %s\n",
+ print_uuid(metadata->img_entry[i].img_props[bank_index].img_uuid)
+ .c_str());
+ printf("\t\t\taccepted : %d\n",
+ metadata->img_entry[i].img_props[bank_index].accepted);
+ }
+ }
+}
diff --git a/components/app/fwu-tool/cmd_print_metadata_v1.h b/components/app/fwu-tool/cmd_print_metadata_v1.h
new file mode 100644
index 000000000..83ac7567a
--- /dev/null
+++ b/components/app/fwu-tool/cmd_print_metadata_v1.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CMD_PRINT_METADATA_V1_H
+#define CMD_PRINT_METADATA_V1_H
+
+#include "app/fwu_app.h"
+
+void cmd_print_metadata_v1(fwu_app &app);
+
+#endif /* CMD_PRINT_METADATA_V1_H */
diff --git a/components/app/fwu-tool/cmd_print_metadata_v2.cpp b/components/app/fwu-tool/cmd_print_metadata_v2.cpp
new file mode 100644
index 000000000..69e09d77c
--- /dev/null
+++ b/components/app/fwu-tool/cmd_print_metadata_v2.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cmd_print_metadata_v2.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <vector>
+
+#include "common/uuid/uuid.h"
+#include "print_uuid.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+#include "protocols/service/fwu/packed-c/metadata_v2.h"
+
+void cmd_print_metadata_v2(fwu_app &app)
+{
+ std::vector<uint8_t> fetched_object;
+ struct uuid_octets object_uuid;
+
+ uuid_guid_octets_from_canonical(&object_uuid, FWU_METADATA_CANONICAL_UUID);
+
+ int status = app.read_object(object_uuid, fetched_object);
+
+ if (status) {
+ printf("Error: failed to read metadata\n");
+ return;
+ }
+
+ if (fetched_object.size() < sizeof(struct fwu_metadata)) {
+ printf("Error: invalid metadata size\n");
+ return;
+ }
+
+ /* Print mandatory metadata header */
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)fetched_object.data();
+
+ printf("\nfwu_metadata (size %zu bytes) :\n", fetched_object.size());
+ printf("\tcrc_32 : 0x%x\n", metadata->crc_32);
+ printf("\tversion : %d\n", metadata->version);
+ printf("\tmetadata_size : %d\n", metadata->metadata_size);
+ printf("\theader_size : %d\n", metadata->header_size);
+ printf("\tactive_index : %d\n", metadata->active_index);
+ printf("\tprevious_active_index : %d\n", metadata->previous_active_index);
+ printf("\tbank_state : 0x%x 0x%x\n", metadata->bank_state[0], metadata->bank_state[1]);
+
+ if (metadata->metadata_size <= metadata->header_size)
+ return;
+
+ size_t fw_store_desc_size = metadata->metadata_size - metadata->header_size;
+
+ if (fw_store_desc_size < sizeof(fwu_fw_store_desc)) {
+ printf("\tInsufficient space for fw store descriptor\n");
+ return;
+ }
+
+ /* Print optional fw store descriptor */
+ struct fwu_fw_store_desc *fw_store_desc =
+ (struct fwu_fw_store_desc *)&fetched_object[metadata->header_size];
+
+ printf("\tfw_store_desc :\n");
+ printf("\t\tnum_banks : %d\n", fw_store_desc->num_banks);
+ printf("\t\tnum_images : %d\n", fw_store_desc->num_images);
+ printf("\t\timg_entry_size : %d\n", fw_store_desc->img_entry_size);
+ printf("\t\tbank_entry_size : %d\n", fw_store_desc->bank_entry_size);
+
+ for (unsigned int i = 0; i < fw_store_desc->num_images; i++) {
+ struct fwu_image_entry *img_entry = &fw_store_desc->img_entry[i];
+
+ printf("\t\timg_entry[%u] :\n", i);
+ printf("\t\t\timg_type_uuid : %s\n", print_uuid(img_entry->img_type_uuid).c_str());
+ printf("\t\t\tlocation_uuid : %s\n", print_uuid(img_entry->location_uuid).c_str());
+
+ for (unsigned int j = 0; j < fw_store_desc->num_banks; j++) {
+ struct fwu_img_bank_info *bank_info = &img_entry->img_bank_info[j];
+
+ printf("\t\t\timg_bank_info[%u] :\n", j);
+ printf("\t\t\t\timg_uuid : %s\n", print_uuid(bank_info->img_uuid).c_str());
+ printf("\t\t\t\taccepted : %d\n", bank_info->accepted);
+ }
+ }
+}
diff --git a/components/app/fwu-tool/cmd_print_metadata_v2.h b/components/app/fwu-tool/cmd_print_metadata_v2.h
new file mode 100644
index 000000000..fc2588602
--- /dev/null
+++ b/components/app/fwu-tool/cmd_print_metadata_v2.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CMD_PRINT_METADATA_V2_H
+#define CMD_PRINT_METADATA_V2_H
+
+#include "app/fwu_app.h"
+
+void cmd_print_metadata_v2(fwu_app &app);
+
+#endif /* CMD_PRINT_METADATA_V2_H */
diff --git a/components/app/fwu-tool/cmd_update_image.cpp b/components/app/fwu-tool/cmd_update_image.cpp
new file mode 100644
index 000000000..06c13a660
--- /dev/null
+++ b/components/app/fwu-tool/cmd_update_image.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cmd_update_image.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "common/uuid/uuid.h"
+
+int cmd_update_image(fwu_app &app, const std::string &img_type_uuid,
+ const std::string &img_filename)
+{
+ FILE *fp = fopen(img_filename.c_str(), "rb");
+
+ if (!fp) {
+ printf("Error: failed to open image file: %s\n", img_filename.c_str());
+ return -1;
+ }
+
+ /* Get file size */
+ fseek(fp, 0, SEEK_END);
+ size_t img_size = ftell(fp);
+ rewind(fp);
+
+ /* Allocate buffer for image data */
+ uint8_t *img_buf = (uint8_t *)malloc(img_size);
+
+ if (!img_buf) {
+ fclose(fp);
+ printf("Error: failed to allocate image buffer\n");
+ return -1;
+ }
+
+ /* Read file contents into buffer */
+ if (fread(img_buf, 1, img_size, fp)) {
+ fclose(fp);
+ free(img_buf);
+ printf("Error: failed to read image file\n");
+ return -1;
+ }
+
+ fclose(fp);
+
+ /* Apply update */
+ struct uuid_octets uuid;
+
+ uuid_guid_octets_from_canonical(&uuid, img_type_uuid.c_str());
+
+ int status = app.update_image(uuid, img_buf, img_size);
+
+ if (status)
+ printf("Error: update image failed\n");
+
+ free(img_buf);
+
+ return status;
+}
diff --git a/components/app/fwu-tool/cmd_update_image.h b/components/app/fwu-tool/cmd_update_image.h
new file mode 100644
index 000000000..20f71bc8c
--- /dev/null
+++ b/components/app/fwu-tool/cmd_update_image.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CMD_UPDATE_IMAGE_H
+#define CMD_UPDATE_IMAGE_H
+
+#include <string>
+
+#include "app/fwu_app.h"
+
+int cmd_update_image(fwu_app &app, const std::string &img_type_uuid,
+ const std::string &img_filename);
+
+#endif /* CMD_UPDATE_IMAGE_H */
diff --git a/components/app/fwu-tool/component.cmake b/components/app/fwu-tool/component.cmake
new file mode 100644
index 000000000..90a07c271
--- /dev/null
+++ b/components/app/fwu-tool/component.cmake
@@ -0,0 +1,38 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the fwu update_agent within a
+# Posix environment as a command-line application. Can be used to apply an
+# update to a disk image file. Uses the same fwu components as a fw deployment
+# of the fwu service.
+#-------------------------------------------------------------------------------
+
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "Mandatory parameter TGT is not defined.")
+endif()
+#-------------------------------------------------------------------------------
+# Common components for fwu posix deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET ${TGT}
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/crc32"
+ "components/common/trace"
+ "components/common/utils"
+)
+
+target_sources(${TGT} PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/fwu_main.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/cmd_update_image.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/cmd_print_image_dir.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/cmd_print_metadata_v1.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/cmd_print_metadata_v2.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/print_uuid.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/app/fwu_app.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/app/metadata_reader.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/app/metadata_v1_reader.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/app/metadata_v2_reader.cpp
+) \ No newline at end of file
diff --git a/components/app/fwu-tool/fwu_main.cpp b/components/app/fwu-tool/fwu_main.cpp
new file mode 100644
index 000000000..ef0fe10f7
--- /dev/null
+++ b/components/app/fwu-tool/fwu_main.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+#include <string>
+#include <sys/stat.h>
+
+#include "cmd_print_image_dir.h"
+#include "cmd_print_metadata_v1.h"
+#include "cmd_print_metadata_v2.h"
+#include "cmd_update_image.h"
+#include "common/uuid/uuid.h"
+#include "app/fwu_app.h"
+
+static bool option_selected(const char *option_switch, int argc, char *argv[]);
+
+static std::string parse_string_option(const char *option_switch, int argc, char *argv[],
+ const char *default_val);
+
+static int parse_numeric_option(const char *option_switch, int argc, char *argv[], int default_val);
+
+static bool file_exists(const std::string &filename);
+
+static void print_usage(void);
+static void print_help(void);
+
+int main(int argc, char *argv[])
+{
+ fwu_app app;
+ std::string disk_img_filename;
+ std::string update_img_filename;
+ std::string img_type_uuid;
+
+ /* Check for help */
+ if (option_selected("-h", argc, argv) || option_selected("-help", argc, argv) ||
+ option_selected("--help", argc, argv)) {
+ print_help();
+ return 0;
+ }
+
+ /* Handle mandatory disk image filename. Must be first argument */
+ if (argc > 1)
+ disk_img_filename = std::string(argv[1]);
+ else {
+ printf("Error: missing disk-filename argument\n");
+ print_usage();
+ return -1;
+ }
+
+ /* Check if disk image file exists */
+ if (!file_exists(disk_img_filename)) {
+ printf("Error: %s does not exist\n", disk_img_filename.c_str());
+ return -1;
+ }
+
+ /* Create fwu configuration based on the input disk image */
+ int status = app.configure(disk_img_filename.c_str());
+
+ if (status) {
+ printf("Error: failed to configure with status: %d\n", status);
+ return -1;
+ }
+
+ /* Attempt to derive boot info from metadata. Assume bootloader booted from the
+ * active index. This can be overridden via command-line parameter.
+ */
+ unsigned int boot_index;
+ unsigned int metadata_version;
+
+ status = app.get_boot_info(boot_index, metadata_version);
+
+ if (status) {
+ printf("No recognised metadata, assume default boot index and version\n");
+
+ boot_index = 0;
+ metadata_version = 2;
+ }
+
+ /* Allow for command-line overrides */
+ boot_index = parse_numeric_option("-boot-index", argc, argv, boot_index);
+ metadata_version = parse_numeric_option("-meta-ver", argc, argv, metadata_version);
+
+ /* Options for printing fwu info */
+ bool is_print_img_dir = option_selected("-dir", argc, argv);
+ bool is_print_metadata = option_selected("-meta", argc, argv);
+
+ /* Parse input image related parameters*/
+ update_img_filename = parse_string_option("-img", argc, argv, "");
+ img_type_uuid = parse_string_option("-img-type", argc, argv, "");
+
+ /* Check if image file exists (if one was specified) */
+ if (!update_img_filename.empty() && !file_exists(update_img_filename)) {
+ printf("Error: %s does not exist\n", update_img_filename.c_str());
+ return -1;
+ }
+
+ /* Check if img type canonical uuid is well formed */
+ if (!img_type_uuid.empty() && !uuid_is_valid(img_type_uuid.c_str())) {
+ printf("Error: image type uuid invalid\n");
+ return -1;
+ }
+
+ /* Initialise the update_agent. Missing or corrupt metadata will get repaired
+ */
+ status = app.init_update_agent(boot_index, metadata_version);
+
+ if (!status) {
+ printf("Update agent started: boot index: %u metadata ver: %u\n", boot_index,
+ metadata_version);
+
+ if (is_print_img_dir)
+ cmd_print_image_dir(app);
+
+ if (is_print_metadata) {
+ if (metadata_version == 1)
+ cmd_print_metadata_v1(app);
+ else if (metadata_version == 2)
+ cmd_print_metadata_v2(app);
+ else
+ printf("Unsupported metadata version\n");
+ }
+
+ if (!update_img_filename.empty() && !img_type_uuid.empty()) {
+ status = cmd_update_image(app, img_type_uuid, update_img_filename);
+
+ } else if (!update_img_filename.empty() || !img_type_uuid.empty()) {
+ printf("Error: both image filename and uuid arguments are needed\n");
+ return -1;
+ }
+ }
+
+ if (!status)
+ printf("OK\n");
+ else
+ printf("Error status: %d\n", status);
+
+ return status;
+}
+
+static bool option_selected(const char *option_switch, int argc, char *argv[])
+{
+ bool is_selected = false;
+
+ for (int i = 1; (i < argc) && !is_selected; ++i) {
+ is_selected = (strcmp(argv[i], option_switch) == 0);
+ }
+
+ return is_selected;
+}
+
+static std::string parse_string_option(const char *option_switch, int argc, char *argv[],
+ const char *default_val)
+{
+ std::string option = std::string(default_val);
+
+ for (int i = 1; i + 1 < argc; ++i) {
+ if (strcmp(argv[i], option_switch) == 0) {
+ option = std::string(argv[i + 1]);
+ break;
+ }
+ }
+
+ return option;
+}
+
+static int parse_numeric_option(const char *option_switch, int argc, char *argv[], int default_val)
+{
+ int option = default_val;
+
+ for (int i = 1; i + 1 < argc; ++i) {
+ if (strcmp(argv[i], option_switch) == 0) {
+ std::istringstream iss(argv[i + 1]);
+ int val;
+
+ iss >> val;
+
+ if (!iss.fail())
+ option = val;
+
+ break;
+ }
+ }
+
+ return option;
+}
+
+static bool file_exists(const std::string &filename)
+{
+ struct stat stat_buf;
+
+ return stat(filename.c_str(), &stat_buf) == 0;
+}
+
+static void print_usage(void)
+{
+ printf("Usage: fwu disk-filename [-dir -meta] [-boot-index number -meta-ver number] "
+ "[-img filename -img-type uuid]\n");
+}
+
+static void print_help(void)
+{
+ print_usage();
+
+ printf("\n");
+ printf("\tdisk-filename\tDisk image file to update\n");
+ printf("\t-dir\t\tPrint image directory\n");
+ printf("\t-meta\t\tPrint FWU metadata\n");
+ printf("\t-boot-index\tOverride default boot index [0..n]\n");
+ printf("\t-meta-ver\tSpecify FWU metadata to use\n");
+ printf("\t-img\t\tFile containing image update\n");
+ printf("\t-img-type\tCanonical UUID of image to update\n");
+}
diff --git a/components/app/fwu-tool/print_uuid.cpp b/components/app/fwu-tool/print_uuid.cpp
new file mode 100644
index 000000000..a65bac17a
--- /dev/null
+++ b/components/app/fwu-tool/print_uuid.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "print_uuid.h"
+
+#include "common/uuid/uuid.h"
+
+std::string print_uuid(const uint8_t *uuid_octets)
+{
+ struct uuid_canonical canonical_uuid;
+
+ uuid_canonical_from_guid_octets(&canonical_uuid, (const struct uuid_octets *)uuid_octets);
+
+ return std::string(canonical_uuid.characters);
+}
diff --git a/components/app/fwu-tool/print_uuid.h b/components/app/fwu-tool/print_uuid.h
new file mode 100644
index 000000000..2e94c8576
--- /dev/null
+++ b/components/app/fwu-tool/print_uuid.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PRINT_UUID_H
+#define PRINT_UUID_H
+
+#include <cstdint>
+#include <string>
+
+std::string print_uuid(const uint8_t *uuid_octets);
+
+#endif /* PRINT_UUID_H */
diff --git a/components/app/platform-inspect/attest_report_fetcher.cpp b/components/app/platform-inspect/attest_report_fetcher.cpp
index 4e43467d2..33977b5d1 100644
--- a/components/app/platform-inspect/attest_report_fetcher.cpp
+++ b/components/app/platform-inspect/attest_report_fetcher.cpp
@@ -25,23 +25,20 @@ static bool verify_token(std::vector<uint8_t> &report, const uint8_t *token, siz
bool fetch_attest_report(std::vector<uint8_t> &report, std::string &error_msg)
{
bool success = false;
- rpc_session_handle rpc_session_handle = NULL;
+ struct rpc_caller_session *rpc_session = NULL;
struct service_context *attest_service_context = NULL;
- int status;
attest_service_context =
- service_locator_query("sn:trustedfirmware.org:attestation:0", &status);
+ service_locator_query("sn:trustedfirmware.org:attestation:0");
if (attest_service_context) {
- struct rpc_caller *caller = NULL;
- rpc_session_handle =
- service_context_open(attest_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+ rpc_session = service_context_open(attest_service_context);
- if (rpc_session_handle) {
+ if (rpc_session) {
- psa_iat_client_init(caller);
- attest_provision_client_init(caller);
+ psa_iat_client_init(rpc_session);
+ attest_provision_client_init(rpc_session);
success = fetch_and_verify(report, error_msg);
}
@@ -58,7 +55,7 @@ bool fetch_attest_report(std::vector<uint8_t> &report, std::string &error_msg)
/* Clean-up context */
psa_iat_client_deinit();
attest_provision_client_deinit();
- service_context_close(attest_service_context, rpc_session_handle);
+ service_context_close(attest_service_context, rpc_session);
service_context_relinquish(attest_service_context);
return success;
diff --git a/components/app/remote-test-runner/remote_test_runner.cpp b/components/app/remote-test-runner/remote_test_runner.cpp
index b819779b5..04c31135e 100644
--- a/components/app/remote-test-runner/remote_test_runner.cpp
+++ b/components/app/remote-test-runner/remote_test_runner.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -46,18 +46,20 @@ int remote_test_runner::execute(int argc, char *argv[])
struct test_summary summary;
std::vector<struct test_result> results;
- if (list_only) {
+ memset(&summary, 0, sizeof(summary));
- test_status = m_client->list_tests(spec, summary, results);
- output_list(summary, results);
- }
- else {
+ test_status = (list_only) ?
+ m_client->list_tests(spec, summary, results) :
+ m_client->run_tests(spec, summary, results);
- test_status = m_client->run_tests(spec, summary, results);
- output_results(summary, results);
- }
+ if (test_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
- if (test_status != TS_TEST_RUNNER_STATUS_SUCCESS) {
+ if (list_only)
+ output_list(summary, results);
+ else
+ output_results(summary, results);
+ }
+ else {
printf("Tests failed to run with error: %d\n", test_status);
}
@@ -119,13 +121,18 @@ void remote_test_runner::output_summary(const struct test_summary &summary)
void remote_test_runner::output_list(const struct test_summary &summary,
const std::vector<struct test_result> &results)
{
+ for (size_t i = 0; i < results.size(); ++i) {
+
+ printf("TEST(%s, %s)\n", results[i].group, results[i].name);
+ }
+ output_summary(summary);
}
void remote_test_runner::output_results(const struct test_summary &summary,
const std::vector<struct test_result> &results)
{
- for (int i = 0; i < results.size(); ++i) {
+ for (size_t i = 0; i < results.size(); ++i) {
printf("TEST(%s, %s) ", results[i].group, results[i].name);
diff --git a/components/app/ts-demo/test/ts-demo_tests.cpp b/components/app/ts-demo/test/ts-demo_tests.cpp
index 2cc8973f9..e78f8a287 100644
--- a/components/app/ts-demo/test/ts-demo_tests.cpp
+++ b/components/app/ts-demo/test/ts-demo_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -16,22 +16,19 @@ TEST_GROUP(TsDemoTests) {
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_crypto_service_context = NULL;
m_crypto_client = NULL;
service_locator_init();
- m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0");
CHECK(m_crypto_service_context);
- m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_crypto_service_context);
+ CHECK(m_rpc_session);
- m_crypto_client = new packedc_crypto_client(caller);
+ m_crypto_client = new packedc_crypto_client(m_rpc_session);
}
void teardown()
@@ -39,14 +36,18 @@ TEST_GROUP(TsDemoTests) {
delete m_crypto_client;
m_crypto_client = NULL;
- service_context_close(m_crypto_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_crypto_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_crypto_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_crypto_service_context);
- m_crypto_service_context = NULL;
+ service_context_relinquish(m_crypto_service_context);
+ m_crypto_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_crypto_service_context;
crypto_client *m_crypto_client;
};
diff --git a/components/app/ts-demo/ts-demo.cpp b/components/app/ts-demo/ts-demo.cpp
index 58b28ef3f..589f3b695 100644
--- a/components/app/ts-demo/ts-demo.cpp
+++ b/components/app/ts-demo/ts-demo.cpp
@@ -169,7 +169,7 @@ public:
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
- psa_set_key_bits(&attributes, 256);
+ psa_set_key_bits(&attributes, 1024);
if (m_verbose) printf("Generating RSA encryption key");
diff --git a/components/common/cbor_dump/cbor_dump.c b/components/common/cbor_dump/cbor_dump.c
index e711d2157..ad01344a2 100644
--- a/components/common/cbor_dump/cbor_dump.c
+++ b/components/common/cbor_dump/cbor_dump.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -24,7 +24,7 @@ static void dump_indent(struct dump_context *dump_ctx, const QCBORItem *item);
static void dump_label(struct dump_context *dump_ctx, const QCBORItem *item);
static void dump_value_separator(struct dump_context *dump_ctx, const QCBORItem *item);
static void dump_value(struct dump_context *dump_ctx, const QCBORItem *item);
-static void dump_text_string(struct dump_context *dump_ctx, const uint8_t *data, size_t len);
+static void dump_text_string(struct dump_context *dump_ctx, const char *data, size_t len);
static void dump_byte_string(struct dump_context *dump_ctx, const uint8_t *data, size_t len);
static const char *dictionary_lookup(struct dump_context *dump_ctx, int64_t id);
@@ -147,7 +147,7 @@ static void dump_value(struct dump_context *dump_ctx, const QCBORItem *item)
}
else if (item->uDataType == QCBOR_TYPE_BYTE_STRING) {
- dump_byte_string(dump_ctx, (const char*)item->val.string.ptr, item->val.string.len);
+ dump_byte_string(dump_ctx, (const uint8_t*)item->val.string.ptr, item->val.string.len);
fprintf(dump_ctx->outfile, "\n");
}
else if (item->uDataType == QCBOR_TYPE_INT64) {
@@ -167,7 +167,7 @@ static void dump_value(struct dump_context *dump_ctx, const QCBORItem *item)
}
}
-static void dump_text_string(struct dump_context *dump_ctx, const uint8_t *data, size_t len)
+static void dump_text_string(struct dump_context *dump_ctx, const char *data, size_t len)
{
char text_buf[len + 1];
diff --git a/components/common/crc32/component.cmake b/components/common/crc32/component.cmake
new file mode 100644
index 000000000..4628b7fcb
--- /dev/null
+++ b/components/common/crc32/component.cmake
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/crc32.c"
+)
+
+if (TS_ENV STREQUAL "arm-linux")
+ target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/crc32_linux.c"
+ )
+endif()
+
+if ((TS_ENV STREQUAL "opteesp") OR (TS_ENV STREQUAL "sp"))
+ target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/crc32_sp.c"
+ )
+endif()
diff --git a/components/common/crc32/crc32.c b/components/common/crc32/crc32.c
new file mode 100644
index 000000000..8c34eb1fd
--- /dev/null
+++ b/components/common/crc32/crc32.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1986 Gary S. Brown
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Based on version by Gary S. Brown. Original source file:
+ * https://web.mit.edu/freebsd/head/sys/libkern/crc32.c
+ */
+
+#ifdef __aarch64__
+#include <arm_acle.h>
+#endif
+#include <stddef.h>
+#include <stdint.h>
+
+#include "crc32.h"
+#include "crc32_discovery.h"
+#include "trace.h"
+
+static const uint32_t crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+static uint32_t crc32_sw(uint32_t crc_prev, const uint8_t *buf, size_t size)
+{
+ uint32_t crc = ~crc_prev;
+
+ if (!buf)
+ return 0;
+
+ while (size > 0) {
+ crc = crc32_tab[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
+ buf++;
+ size--;
+ }
+
+ return ~crc;
+}
+
+#if __ARM_FEATURE_CRC32
+static uint32_t crc32_armv8a(uint32_t crc_prev, const uint8_t *buf, size_t size)
+{
+ uint32_t crc = ~crc_prev;
+
+ if (!buf)
+ return 0;
+
+ while (size > 0) {
+ crc = __crc32b(crc, *buf);
+ buf++;
+ size--;
+ }
+
+ return ~crc;
+}
+#endif
+
+uint32_t (*crc32)(uint32_t crc_prev, const uint8_t *buf, size_t size) = crc32_sw;
+
+void crc32_init(void)
+{
+#if __ARM_FEATURE_CRC32
+ if (crc32_armv8a_hw_available()) {
+ DMSG("Using crc32_armv8a CRC32 implementation");
+ crc32 = crc32_armv8a;
+ }
+#endif
+}
+
+/* For compatability with TF-A components */
+uint32_t tf_crc32(uint32_t crc, const unsigned char *buf, size_t size)
+{
+ return crc32(crc, buf, size);
+}
diff --git a/components/common/crc32/crc32.h b/components/common/crc32/crc32.h
new file mode 100644
index 000000000..ae185cc7d
--- /dev/null
+++ b/components/common/crc32/crc32.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef COMMON_CRC32_H
+#define COMMON_CRC32_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Initialize CRC32 to use HW acceleration if available
+ */
+void crc32_init(void);
+
+/**
+ * \brief Calculate a CRC32 over the provided data
+ *
+ * \param[in] crc_prev The starting CRC for previous data
+ * \param[in] buf The buffer to calculate the CRC over
+ * \param[in] size Number of bytes in the buffer
+ *
+ * \return The calculated CRC32
+ */
+extern uint32_t (*crc32)(uint32_t crc_prev, const uint8_t *buf, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COMMON_CRC32_H */
diff --git a/components/common/crc32/crc32_discovery.h b/components/common/crc32/crc32_discovery.h
new file mode 100644
index 000000000..77a22d180
--- /dev/null
+++ b/components/common/crc32/crc32_discovery.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRC32_DISCOVERY_H
+#define CRC32_DISCOVERY_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool crc32_armv8a_hw_available(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CRC32_DISCOVERY_H */
diff --git a/components/common/crc32/crc32_linux.c b/components/common/crc32/crc32_linux.c
new file mode 100644
index 000000000..d6dd8b602
--- /dev/null
+++ b/components/common/crc32/crc32_linux.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <sys/auxv.h>
+
+#include "crc32_discovery.h"
+
+bool crc32_armv8a_hw_available(void)
+{
+ unsigned long hwcaps = getauxval(AT_HWCAP);
+ return (hwcaps & HWCAP_CRC32) == HWCAP_CRC32;
+}
diff --git a/components/common/crc32/crc32_sp.c b/components/common/crc32/crc32_sp.c
new file mode 100644
index 000000000..9e2db8e11
--- /dev/null
+++ b/components/common/crc32/crc32_sp.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "config/interface/config_store.h"
+#include "crc32_discovery.h"
+
+bool crc32_armv8a_hw_available(void)
+{
+ uint32_t value = 0;
+
+ if (!config_store_query(CONFIG_CLASSIFIER_HW_FEATURE, "crc32", 0, &value, sizeof(value)))
+ return false;
+
+ return value != 0;
+}
diff --git a/components/service/discovery/client/component.cmake b/components/common/crc32/test/component.cmake
index ce48d006d..34af66d3f 100644
--- a/components/service/discovery/client/component.cmake
+++ b/components/common/crc32/test/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,5 +9,5 @@ if (NOT DEFINED TGT)
endif()
target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/discovery_client.c"
+ "${CMAKE_CURRENT_LIST_DIR}/crc32_test.cpp"
)
diff --git a/components/common/crc32/test/crc32_test.cpp b/components/common/crc32/test/crc32_test.cpp
new file mode 100644
index 000000000..5e1ea8d6c
--- /dev/null
+++ b/components/common/crc32/test/crc32_test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/crc32/crc32.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(Crc32Tests)
+{
+ TEST_SETUP()
+ {
+ crc32_init();
+ }
+};
+
+/*
+ * Expected results obtained from: https://crc32.online/
+ */
+TEST(Crc32Tests, shortString)
+{
+ const unsigned char test_input[] = "Hello";
+ uint32_t expected_result = 0xf7d18982;
+ uint32_t input_crc = 0;
+
+ uint32_t result = crc32(input_crc, test_input, sizeof(test_input) - 1);
+
+ UNSIGNED_LONGS_EQUAL(expected_result, result);
+}
+
+TEST(Crc32Tests, longString)
+{
+ const unsigned char test_input[] =
+ "The boy stood on the burning deck Whence all but he had fled";
+ uint32_t expected_result = 0x1f11704c;
+ uint32_t input_crc = 0;
+
+ uint32_t result = crc32(input_crc, test_input, sizeof(test_input) - 1);
+
+ UNSIGNED_LONGS_EQUAL(expected_result, result);
+}
+
+TEST(Crc32Tests, multiPart)
+{
+ const unsigned char test_input_1[] =
+ "The boy stood on the burning deck ";
+ const unsigned char test_input_2[] =
+ "Whence all but he had fled";
+
+ uint32_t expected_result = 0x1f11704c;
+ uint32_t result = 0;
+
+ result = crc32(result, test_input_1, sizeof(test_input_1) - 1);
+ result = crc32(result, test_input_2, sizeof(test_input_2) - 1);
+
+ UNSIGNED_LONGS_EQUAL(expected_result, result);
+} \ No newline at end of file
diff --git a/components/common/fdt/component.cmake b/components/common/fdt/component.cmake
new file mode 100644
index 000000000..2c32e1841
--- /dev/null
+++ b/components/common/fdt/component.cmake
@@ -0,0 +1,15 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fdt_helpers.c"
+)
+
+include(${TS_ROOT}/external/libfdt/libfdt.cmake)
diff --git a/components/common/fdt/fdt_helpers.c b/components/common/fdt/fdt_helpers.c
new file mode 100644
index 000000000..5a6f94982
--- /dev/null
+++ b/components/common/fdt/fdt_helpers.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "fdt_helpers.h"
+
+bool dt_get_u32(const void *fdt, int node, const char *prop_name, uint32_t *prop_val)
+{
+ const fdt32_t *u32_prop = NULL;
+ int len = 0;
+
+ if (!fdt || !prop_name || !prop_val)
+ return false;
+
+ u32_prop = fdt_getprop(fdt, node, prop_name, &len);
+ if (!u32_prop || len != sizeof(*u32_prop))
+ return false;
+
+ *prop_val = fdt32_to_cpu(*u32_prop);
+
+ return true;
+}
+
+bool dt_get_u64(const void *fdt, int node, const char *prop_name, uint64_t *prop_val)
+{
+ const fdt64_t *u64_prop = NULL;
+ int len = 0;
+
+ if (!fdt || !prop_name || !prop_val)
+ return false;
+
+ u64_prop = fdt_getprop(fdt, node, prop_name, &len);
+ if (!u64_prop || len != sizeof(*u64_prop))
+ return false;
+
+ *prop_val = fdt64_to_cpu(*u64_prop);
+
+ return true;
+}
+
+bool dt_get_u32_by_offset(const void *fdt, int offset, const char **prop_name, uint32_t *prop_val)
+{
+ const fdt32_t *u32_prop = NULL;
+ int len = 0;
+
+ if (!fdt || !prop_name || !prop_val)
+ return false;
+
+ u32_prop = fdt_getprop_by_offset(fdt, offset, prop_name, &len);
+ if (!u32_prop || len != sizeof(*u32_prop) || !(*prop_name))
+ return false;
+
+ *prop_val = fdt32_to_cpu(*u32_prop);
+
+ return true;
+}
+
+bool dt_get_u64_by_offset(const void *fdt, int offset, const char **prop_name, uint64_t *prop_val)
+{
+ const fdt64_t *u64_prop = NULL;
+ int len = 0;
+
+ if (!fdt || !prop_name || !prop_val)
+ return false;
+
+ u64_prop = fdt_getprop_by_offset(fdt, offset, prop_name, &len);
+ if (!u64_prop || len != sizeof(*u64_prop) || !(*prop_name))
+ return false;
+
+ *prop_val = fdt64_to_cpu(*u64_prop);
+
+ return true;
+}
diff --git a/components/common/fdt/fdt_helpers.h b/components/common/fdt/fdt_helpers.h
new file mode 100644
index 000000000..66535ca21
--- /dev/null
+++ b/components/common/fdt/fdt_helpers.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <libfdt.h>
+#include <stdbool.h>
+
+bool dt_get_u32(const void *fdt, int node, const char *prop_name, uint32_t *prop_val);
+bool dt_get_u64(const void *fdt, int node, const char *prop_name, uint64_t *prop_val);
+bool dt_get_u32_by_offset(const void *fdt, int offset, const char **prop_name, uint32_t *prop_val);
+bool dt_get_u64_by_offset(const void *fdt, int offset, const char **prop_name, uint64_t *prop_val);
diff --git a/components/common/libc/component.cmake b/components/common/libc/component.cmake
new file mode 100644
index 000000000..042117bab
--- /dev/null
+++ b/components/common/libc/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_include_directories(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/include"
+)
diff --git a/components/common/libc/include/assert_fail_handler.h b/components/common/libc/include/assert_fail_handler.h
new file mode 100644
index 000000000..7f36f25ae
--- /dev/null
+++ b/components/common/libc/include/assert_fail_handler.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef ASSERT_FAIL_HANDLER_H_
+#define ASSERT_FAIL_HANDLER_H_
+
+#include "compiler.h"
+
+/*
+ * Generic assert fail handler function definition. Should be implemented by the environment.
+ */
+void __noreturn assert_fail_handler(const char *file, int line,
+ const char *func, const char *failedexpr);
+
+#endif /* ASSERT_FAIL_HANDLER_H_ */
diff --git a/components/common/libc/include/libc_init.h b/components/common/libc/include/libc_init.h
new file mode 100644
index 000000000..28988d5c5
--- /dev/null
+++ b/components/common/libc/include/libc_init.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBC_INIT_H_
+#define LIBC_INIT_H_
+
+/*
+ * Generic libc init function. Implemented by the newlib external, should be called by the
+ * environment on boot.
+ */
+void libc_init(void);
+
+#endif /* LIBC_INIT_H_ */
diff --git a/components/common/trace/trace.c b/components/common/trace/trace.c
index bc7f0a977..0b8cb53d7 100644
--- a/components/common/trace/trace.c
+++ b/components/common/trace/trace.c
@@ -30,10 +30,18 @@ void trace_printf(const char *func, int line, int level, const char *fmt, ...)
if (offset < sizeof(buffer)) {
va_start(ap, fmt);
- vsnprintf(buffer + offset, sizeof(buffer) - offset, fmt, ap);
+ offset += vsnprintf(buffer + offset, sizeof(buffer) - offset, fmt, ap);
va_end(ap);
}
+ if (offset < sizeof(buffer) - 2) {
+ buffer[offset] = '\n';
+ buffer[offset + 1] = '\0';
+ } else {
+ buffer[sizeof(buffer) - 2] = '\n';
+ buffer[sizeof(buffer) - 1] = '\0';
+ }
+
trace_puts(buffer);
}
#endif
diff --git a/components/common/utils/component.cmake b/components/common/utils/component.cmake
index 363a464ab..d0765ce7c 100644
--- a/components/common/utils/component.cmake
+++ b/components/common/utils/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -11,5 +11,11 @@ endif()
target_include_directories(${TGT}
PUBLIC
- "${CMAKE_CURRENT_LIST_DIR}/include"
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
+ "$<INSTALL_INTERFACE:${TS_ENV}/include>"
)
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+ "${CMAKE_CURRENT_LIST_DIR}/include/util.h"
+ "${CMAKE_CURRENT_LIST_DIR}/include/compiler.h"
+ ) \ No newline at end of file
diff --git a/components/common/utils/include/compiler.h b/components/common/utils/include/compiler.h
index d0354c542..075530b0e 100644
--- a/components/common/utils/include/compiler.h
+++ b/components/common/utils/include/compiler.h
@@ -7,7 +7,15 @@
#ifndef COMPILER_H
#define COMPILER_H
+/* Some standard library implementations define some macros defined in this
+ * file without protection against redefinition. Depending on inclusion order
+ * through other file this results in compiler warnings being triggered.
+ * Including cdefs.h here makes the standard library implementation the
+ * definitive owner and thus solves the problem.
+ */
+#ifdef ENABLE_CDEFSH_FIX
#include <sys/cdefs.h>
+#endif
/*
* Macros that should be used instead of using __attribute__ directly to
diff --git a/components/common/utils/include/util.h b/components/common/utils/include/util.h
index 03ab476d0..c55f3e1d9 100644
--- a/components/common/utils/include/util.h
+++ b/components/common/utils/include/util.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
*/
#ifndef UTIL_H
#define UTIL_H
@@ -48,8 +49,8 @@
~((__typeof__(v))(size) - 1))
#define ROUNDUP_OVERFLOW(v, size, res) (__extension__({ \
- typeof(*(res)) __roundup_tmp = 0; \
- typeof(v) __roundup_mask = (typeof(v))(size) - 1; \
+ __typeof__(*(res)) __roundup_tmp = 0; \
+ __typeof__(v) __roundup_mask = (__typeof__(v))(size) - 1; \
\
ADD_OVERFLOW((v), __roundup_mask, &__roundup_tmp) ? 1 : \
(void)(*(res) = __roundup_tmp & ~__roundup_mask), 0; \
@@ -64,8 +65,8 @@
* num_pages = ROUNDUP_DIV(num_bytes, SMALL_PAGE_SIZE);
*/
#define ROUNDUP_DIV(x, y) (__extension__({ \
- typeof(x) __roundup_x = (x); \
- typeof(y) __roundup_mask = (typeof(x))(y) - 1; \
+ __typeof__(x) __roundup_x = (x); \
+ __typeof__(y) __roundup_mask = (__typeof__(x))(y) - 1; \
\
(__roundup_x / (y)) + (__roundup_x & __roundup_mask ? 1 : 0); \
}))
@@ -98,7 +99,7 @@
#define container_of(ptr, type, member) \
(__extension__({ \
- const typeof(((type *)0)->member) *__ptr = (ptr); \
+ const __typeof__(((type *)0)->member) *__ptr = (ptr); \
(type *)((unsigned long)(__ptr) - offsetof(type, member)); \
}))
diff --git a/components/common/uuid/test/uuid_tests.cpp b/components/common/uuid/test/uuid_tests.cpp
index 03f4f8781..a568a88e1 100644
--- a/components/common/uuid/test/uuid_tests.cpp
+++ b/components/common/uuid/test/uuid_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,100 +14,168 @@ TEST_GROUP(UuidTests) {
TEST(UuidTests, parseValidUuidLowerCase) {
- /* A valid UUID unsing lower-case */
- const char *uuid_text = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
- CHECK(uuid_is_valid(uuid_text));
+ /* A valid UUID using lower-case */
+ const char *uuid_text = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ CHECK(uuid_is_valid(uuid_text));
- const uint8_t expected_bytes[] =
- {0xd9,0xdf,0x52,0xd5,
- 0x16,0xa2,
- 0x4b,0xb2,
- 0x9a,0xa4,
- 0xd2,0x6d,0x3b,0x84,0xe8,0xc0};
+ const uint8_t expected_bytes[] =
+ {0xd9,0xdf,0x52,0xd5,
+ 0x16,0xa2,
+ 0x4b,0xb2,
+ 0x9a,0xa4,
+ 0xd2,0x6d,0x3b,0x84,0xe8,0xc0};
- uint8_t byte_array[UUID_OCTETS_LEN];
- memset(byte_array, 0, sizeof(byte_array));
+ uint8_t byte_array[UUID_OCTETS_LEN];
+ memset(byte_array, 0, sizeof(byte_array));
- CHECK(uuid_parse_to_octets(uuid_text, byte_array, sizeof(byte_array)));
- CHECK(memcmp(byte_array, expected_bytes, UUID_OCTETS_LEN) == 0);
+ CHECK(uuid_parse_to_octets(uuid_text, byte_array, sizeof(byte_array)));
+ CHECK(memcmp(byte_array, expected_bytes, UUID_OCTETS_LEN) == 0);
}
TEST(UuidTests, parseValidUuidMixedCase) {
- /* A valid UUID unsing mixed-case */
- const char *uuid_text = "D9df52d5-16a2-4bB2-9aa4-d26d3b84E8c0";
- CHECK(uuid_is_valid(uuid_text));
+ /* A valid UUID using mixed-case */
+ const char *uuid_text = "D9df52d5-16a2-4bB2-9aa4-d26d3b84E8c0";
+ CHECK(uuid_is_valid(uuid_text));
- const uint8_t expected_bytes[] =
- {0xd9,0xdf,0x52,0xd5,
- 0x16,0xa2,
- 0x4b,0xb2,
- 0x9a,0xa4,
- 0xd2,0x6d,0x3b,0x84,0xe8,0xc0};
+ const uint8_t expected_bytes[] =
+ {0xd9,0xdf,0x52,0xd5,
+ 0x16,0xa2,
+ 0x4b,0xb2,
+ 0x9a,0xa4,
+ 0xd2,0x6d,0x3b,0x84,0xe8,0xc0};
- uint8_t byte_array[UUID_OCTETS_LEN];
- memset(byte_array, 0, sizeof(byte_array));
+ uint8_t byte_array[UUID_OCTETS_LEN];
+ memset(byte_array, 0, sizeof(byte_array));
- CHECK(uuid_parse_to_octets(uuid_text, byte_array, sizeof(byte_array)));
- CHECK(memcmp(byte_array, expected_bytes, UUID_OCTETS_LEN) == 0);
+ CHECK(uuid_parse_to_octets(uuid_text, byte_array, sizeof(byte_array)));
+ CHECK(memcmp(byte_array, expected_bytes, UUID_OCTETS_LEN) == 0);
}
TEST(UuidTests, parseUuidInUrn) {
- /* A valid UUID embedded in a urn */
- const char *urn_text = "urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66:0";
- CHECK(uuid_is_valid(&urn_text[9]));
+ /* A valid UUID embedded in a urn */
+ const char *urn_text = "urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66:0";
+ CHECK(uuid_is_valid(&urn_text[9]));
- const uint8_t expected_bytes[] =
- {0x6e,0x8b,0xc4,0x30,
- 0x9c,0x3a,
- 0x11,0xd9,
- 0x96,0x69,
- 0x08,0x00,0x20,0x0c,0x9a,0x66};
+ const uint8_t expected_bytes[] =
+ {0x6e,0x8b,0xc4,0x30,
+ 0x9c,0x3a,
+ 0x11,0xd9,
+ 0x96,0x69,
+ 0x08,0x00,0x20,0x0c,0x9a,0x66};
- uint8_t byte_array[UUID_OCTETS_LEN];
- memset(byte_array, 0, sizeof(byte_array));
+ uint8_t byte_array[UUID_OCTETS_LEN];
+ memset(byte_array, 0, sizeof(byte_array));
- CHECK(uuid_parse_to_octets(&urn_text[9], byte_array, sizeof(byte_array)));
- CHECK(memcmp(byte_array, expected_bytes, UUID_OCTETS_LEN) == 0);
+ CHECK(uuid_parse_to_octets(&urn_text[9], byte_array, sizeof(byte_array)));
+ CHECK(memcmp(byte_array, expected_bytes, UUID_OCTETS_LEN) == 0);
}
TEST(UuidTests, parseError) {
- /* Invalid digit */
- const char *broken1 = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8X0";
- CHECK(!uuid_is_valid(broken1));
+ /* Invalid digit */
+ const char *broken1 = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8X0";
+ CHECK(!uuid_is_valid(broken1));
- /* Invalid separator */
- const char *broken2 = "d9df52d5-16a2-4bb2-9aa4_d26d3b84e8c0";
- CHECK(!uuid_is_valid(broken2));
+ /* Invalid separator */
+ const char *broken2 = "d9df52d5-16a2-4bb2-9aa4_d26d3b84e8c0";
+ CHECK(!uuid_is_valid(broken2));
- /* Too short */
- const char *broken3 = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c";
- CHECK(!uuid_is_valid(broken3));
+ /* Too short */
+ const char *broken3 = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c";
+ CHECK(!uuid_is_valid(broken3));
- /* Zero length */
- const char *broken4 = "";
- CHECK(!uuid_is_valid(broken4));
+ /* Zero length */
+ const char *broken4 = "";
+ CHECK(!uuid_is_valid(broken4));
}
-TEST(UuidTests, parseValidUuidToReversed) {
+TEST(UuidTests, parseValidUuidToGuidOctets) {
- /* A valid UUID unsing lower-case */
- const char *uuid_text = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
- CHECK(uuid_is_valid(uuid_text));
+ /* A valid UUID using lower-case */
+ const char *uuid_text = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ CHECK(uuid_is_valid(uuid_text));
- /* Reversed ouput is expected to be */
- const uint8_t expected_bytes[] =
- {0xd5,0x52,0xdf,0xd9,
- 0xa2,0x16,
- 0xb2,0x4b,
- 0x9a,0xa4,
- 0xd2,0x6d,0x3b,0x84,0xe8,0xc0};
+ /* GUID octet representation is expected to be */
+ const uint8_t expected_bytes[] =
+ {0xd5,0x52,0xdf,0xd9,
+ 0xa2,0x16,
+ 0xb2,0x4b,
+ 0x9a,0xa4,
+ 0xd2,0x6d,0x3b,0x84,0xe8,0xc0};
- uint8_t byte_array[UUID_OCTETS_LEN];
- memset(byte_array, 0, sizeof(byte_array));
+ uint8_t byte_array[UUID_OCTETS_LEN];
+ memset(byte_array, 0, sizeof(byte_array));
- CHECK(uuid_parse_to_octets_reversed(uuid_text, byte_array, sizeof(byte_array)));
- CHECK(memcmp(byte_array, expected_bytes, UUID_OCTETS_LEN) == 0);
+ CHECK(uuid_parse_to_guid_octets(uuid_text, byte_array, sizeof(byte_array)));
+ CHECK(memcmp(byte_array, expected_bytes, UUID_OCTETS_LEN) == 0);
}
+
+TEST(UuidTests, checkOctetsFromCanonical) {
+
+ /* A valid UUID */
+ const char *uuid_text = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ CHECK(uuid_is_valid(uuid_text));
+
+ struct uuid_octets result1;
+
+ memset(&result1, 0x22, sizeof(result1));
+ uuid_octets_from_canonical(&result1, uuid_text);
+
+ struct uuid_octets result2;
+
+ memset(&result2, 0xaa, sizeof(result2));
+ size_t valid_chars = uuid_parse_to_octets(uuid_text,
+ result2.octets, sizeof(result2.octets));
+
+ UNSIGNED_LONGS_EQUAL(UUID_CANONICAL_FORM_LEN, valid_chars);
+ MEMCMP_EQUAL(result2.octets, result1.octets, sizeof(result2.octets));
+}
+
+TEST(UuidTests, checkIsEqualOperation) {
+
+ struct uuid_octets uuid_a;
+ struct uuid_octets uuid_b;
+
+ uuid_guid_octets_from_canonical(&uuid_a, "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0");
+ uuid_guid_octets_from_canonical(&uuid_b, "2435fa44-0951-4ce9-bcf4-1ad08d77cbff");
+
+ CHECK_FALSE(uuid_is_equal(uuid_a.octets, uuid_b.octets));
+ CHECK_TRUE(uuid_is_equal(uuid_a.octets, uuid_a.octets));
+ CHECK_TRUE(uuid_is_equal(uuid_b.octets, uuid_b.octets));
+}
+
+TEST(UuidTests, checkNilUuidOperations) {
+
+ struct uuid_octets uuid;
+
+ uuid_guid_octets_from_canonical(&uuid, "00000000-0000-0000-0000-000000000000");
+ CHECK_TRUE(uuid_is_equal(uuid_get_nil()->octets, uuid.octets));
+ CHECK_TRUE(uuid_is_nil(uuid.octets));
+
+ uuid_guid_octets_from_canonical(&uuid, "00000000-0000-0000-0000-000000000003");
+ CHECK_FALSE(uuid_is_nil(uuid.octets));
+}
+
+TEST(UuidTests, roundTrip) {
+
+ /* A valid UUID using lower-case */
+ const char *uuid_text = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ CHECK_TRUE(uuid_is_valid(uuid_text));
+
+ struct uuid_octets uuid;
+ struct uuid_canonical canonical_uuid;
+
+ /* Round trip using standard octet order */
+ uuid_octets_from_canonical(&uuid, uuid_text);
+ uuid_canonical_from_octets(&canonical_uuid, &uuid);
+
+ MEMCMP_EQUAL(uuid_text, canonical_uuid.characters, sizeof(canonical_uuid.characters));
+
+ /* Round trip using GUID octet order */
+ uuid_guid_octets_from_canonical(&uuid, uuid_text);
+ uuid_canonical_from_guid_octets(&canonical_uuid, &uuid);
+
+ MEMCMP_EQUAL(uuid_text, canonical_uuid.characters, sizeof(canonical_uuid.characters));
+} \ No newline at end of file
diff --git a/components/common/uuid/uuid.c b/components/common/uuid/uuid.c
index 5d4644181..16b673056 100644
--- a/components/common/uuid/uuid.c
+++ b/components/common/uuid/uuid.c
@@ -1,10 +1,11 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "uuid.h"
+#include <assert.h>
#include <string.h>
#include <ctype.h>
@@ -22,6 +23,20 @@ static uint8_t hex_to_nibble(char hex)
return nibble;
}
+static char nibble_to_hex(uint8_t nibble)
+{
+ char hex;
+
+ nibble &= 0x0f;
+
+ if (nibble <= 9)
+ hex = '0' + nibble;
+ else
+ hex = 'a' + nibble - 10;
+
+ return hex;
+}
+
static uint8_t hex_to_byte(const char *hex)
{
/* Takes a validated input and returns the byte value */
@@ -33,10 +48,11 @@ static uint8_t hex_to_byte(const char *hex)
size_t uuid_is_valid(const char *canonical_form)
{
size_t valid_chars = 0;
- size_t input_len = strlen(canonical_form);
-
- if (input_len >= UUID_CANONICAL_FORM_LEN) {
+ /* Note that a valid canonical uuid may be part of a longer string
+ * such as a urn.
+ */
+ if (!memchr(canonical_form, '\0', UUID_CANONICAL_FORM_LEN)) {
size_t i;
valid_chars = UUID_CANONICAL_FORM_LEN;
@@ -46,7 +62,7 @@ size_t uuid_is_valid(const char *canonical_form)
if (canonical_form[i] != '-') return 0;
}
else {
- if (!isxdigit(canonical_form[i])) return 0;
+ if (!isxdigit((int)canonical_form[i])) return 0;
}
}
}
@@ -54,6 +70,23 @@ size_t uuid_is_valid(const char *canonical_form)
return valid_chars;
}
+bool uuid_is_equal(const uint8_t *octets_a, const uint8_t *octets_b)
+{
+ return memcmp(octets_a, octets_b, UUID_OCTETS_LEN) == 0;
+}
+
+bool uuid_is_nil(const uint8_t *octets)
+{
+ return memcmp(uuid_get_nil()->octets, octets, UUID_OCTETS_LEN) == 0;
+}
+
+const struct uuid_octets *uuid_get_nil(void)
+{
+ static const struct uuid_octets nil_uuid = {0};
+
+ return &nil_uuid;
+}
+
size_t uuid_parse_to_octets(const char *canonical_form, uint8_t *buf, size_t buf_size)
{
size_t octet_index = 0;
@@ -105,41 +138,106 @@ size_t uuid_parse_to_octets(const char *canonical_form, uint8_t *buf, size_t buf
}
/*
- * TODO: Temorary workaround for optee compatibility
- * The byte order is reversed for the first 4 bytes, then 2 bytes, then 2 bytes.
- * This is because the UUID type in OP-TEE consists of an uint32_t, 2x uint16_t,
- * then uint8_t array.
+ * The byte order is reversed for the integer sections of the UUID. Converts
+ * from standard to GUID octet representations an visa versa.
*/
-size_t uuid_parse_to_octets_reversed(const char *canonical_form, uint8_t *buf, size_t buf_size)
+void uuid_reverse_octets(const struct uuid_octets *input_octets,
+ uint8_t *buf, size_t buf_size)
+{
+ if (buf_size >= UUID_OCTETS_LEN) {
+ /* Reverse bytes in each section */
+ buf[0] = input_octets->octets[3];
+ buf[1] = input_octets->octets[2];
+ buf[2] = input_octets->octets[1];
+ buf[3] = input_octets->octets[0];
+
+ buf[4] = input_octets->octets[5];
+ buf[5] = input_octets->octets[4];
+
+ buf[6] = input_octets->octets[7];
+ buf[7] = input_octets->octets[6];
+
+ buf[8] = input_octets->octets[8];
+ buf[9] = input_octets->octets[9];
+
+ buf[10] = input_octets->octets[10];
+ buf[11] = input_octets->octets[11];
+ buf[12] = input_octets->octets[12];
+ buf[13] = input_octets->octets[13];
+ buf[14] = input_octets->octets[14];
+ buf[15] = input_octets->octets[15];
+ }
+}
+
+size_t uuid_parse_to_guid_octets(const char *canonical_form,
+ uint8_t *buf, size_t buf_size)
{
size_t valid_chars;
- uint8_t standard_octets[UUID_OCTETS_LEN];
+ struct uuid_octets standard_encoding;
- valid_chars = uuid_parse_to_octets(canonical_form, standard_octets, sizeof(standard_octets));
+ valid_chars = uuid_parse_to_octets(canonical_form,
+ standard_encoding.octets, sizeof(standard_encoding.octets));
- if ((valid_chars == UUID_CANONICAL_FORM_LEN) && (buf_size >= UUID_OCTETS_LEN)) {
- /* Reverse bytes in each section */
- buf[0] = standard_octets[3];
- buf[1] = standard_octets[2];
- buf[2] = standard_octets[1];
- buf[3] = standard_octets[0];
-
- buf[4] = standard_octets[5];
- buf[5] = standard_octets[4];
-
- buf[6] = standard_octets[7];
- buf[7] = standard_octets[6];
-
- buf[8] = standard_octets[8];
- buf[9] = standard_octets[9];
-
- buf[10] = standard_octets[10];
- buf[11] = standard_octets[11];
- buf[12] = standard_octets[12];
- buf[13] = standard_octets[13];
- buf[14] = standard_octets[14];
- buf[15] = standard_octets[15];
+ if (valid_chars == UUID_CANONICAL_FORM_LEN) {
+
+ uuid_reverse_octets(&standard_encoding, buf, buf_size);
}
return valid_chars;
}
+
+void uuid_octets_from_canonical(struct uuid_octets *uuid_octets,
+ const char *canonical_form)
+{
+ size_t valid_chars = uuid_parse_to_octets(canonical_form,
+ uuid_octets->octets, sizeof(uuid_octets->octets));
+
+ /* Input string is assumed to be valid. Should not be used if canonical
+ * string originates from an untrusted source.
+ */
+ assert(valid_chars == UUID_CANONICAL_FORM_LEN);
+}
+
+void uuid_guid_octets_from_canonical(struct uuid_octets *uuid_octets,
+ const char *canonical_form)
+{
+ size_t valid_chars = uuid_parse_to_guid_octets(canonical_form,
+ uuid_octets->octets, sizeof(uuid_octets->octets));
+
+ assert(valid_chars == UUID_CANONICAL_FORM_LEN);
+}
+
+void uuid_canonical_from_octets(struct uuid_canonical *canonical_form,
+ const struct uuid_octets *uuid_octets)
+{
+ unsigned int octet_index = 0;
+ unsigned int char_index = 0;
+
+ while (octet_index < UUID_OCTETS_LEN) {
+
+ canonical_form->characters[char_index++] =
+ nibble_to_hex(uuid_octets->octets[octet_index] >> 4);
+
+ canonical_form->characters[char_index++] =
+ nibble_to_hex(uuid_octets->octets[octet_index] & 0x0f);
+
+ ++octet_index;
+
+ if ((octet_index == 4) ||
+ (octet_index == 6) ||
+ (octet_index == 8) ||
+ (octet_index == 10))
+ canonical_form->characters[char_index++] = '-';
+ }
+
+ canonical_form->characters[char_index] = '\0';
+}
+
+void uuid_canonical_from_guid_octets(struct uuid_canonical *canonical_form,
+ const struct uuid_octets *uuid_octets)
+{
+ struct uuid_octets reversed_octets;
+
+ uuid_reverse_octets(uuid_octets, reversed_octets.octets, sizeof(reversed_octets.octets));
+ uuid_canonical_from_octets(canonical_form, &reversed_octets);
+}
diff --git a/components/common/uuid/uuid.h b/components/common/uuid/uuid.h
index e45e37afc..4333ad2b4 100644
--- a/components/common/uuid/uuid.h
+++ b/components/common/uuid/uuid.h
@@ -1,17 +1,18 @@
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef UUID_H
-#define UUID_H
+#ifndef COMMON_UUID_H
+#define COMMON_UUID_H
#include <stddef.h>
+#include <stdbool.h>
#include <stdint.h>
-#define UUID_OCTETS_LEN (16)
-#define UUID_CANONICAL_FORM_LEN (36)
+#define UUID_OCTETS_LEN (16)
+#define UUID_CANONICAL_FORM_LEN (36)
#ifdef __cplusplus
@@ -20,10 +21,19 @@ extern "C" {
/*
* Structure for holding an octet representation of a UUID.
+ *
+ * There are two common byte orderings for octet representations of UUIDs.
+ * RFC4122 specifies that integer fields from the UUID data structure
+ * should be presented with most significant bytes first. An alternative
+ * byte ordering, used by UEFI, presents integer values with the reverse
+ * byte order (little Endian). The UEFI specification uses the GUID rather
+ * than UUID acronym. To distinguish between the two octet representations,
+ * functions that assume the little Endian octet encoding include 'guid' in
+ * the function name.
*/
struct uuid_octets
{
- uint8_t octets[UUID_OCTETS_LEN];
+ uint8_t octets[UUID_OCTETS_LEN];
};
/*
@@ -31,33 +41,81 @@ struct uuid_octets
*/
struct uuid_canonical
{
- char characters[UUID_CANONICAL_FORM_LEN + 1];
+ char characters[UUID_CANONICAL_FORM_LEN + 1];
};
/*
- * Check if uuid string in canonical form is valid. Returns the number of
- * valid characters. This will either be UUID_CANONICAL_FORM_LEN or zero
+ * Check if uuid string in canonical form is valid. Returns the number of
+ * valid characters. This will either be UUID_CANONICAL_FORM_LEN or zero
* if the string is invalid in some way.
*/
size_t uuid_is_valid(const char *canonical_form);
/*
- * Parses a uuid string in canonical string form, outputing as an array of bytes.
- * Returns the number of characters parsed from the input string. Returns zero
- * if there is a parsing error.
+ * Check if two octet uuid representations are equal
+ */
+bool uuid_is_equal(const uint8_t *octets_a, const uint8_t *octets_b);
+
+/*
+ * Check if octets represent a nil uuid
+ */
+bool uuid_is_nil(const uint8_t *octets);
+
+/*
+ * Return a const nil uuid
+ */
+const struct uuid_octets *uuid_get_nil(void);
+
+/*
+ * Parses a uuid string in canonical string form, outputting as an array of bytes
+ * in the standard big endian byte order. Returns the number of characters parsed
+ * from the input string. Returns zero if there is a parsing error.
+ */
+size_t uuid_parse_to_octets(const char *canonical_form,
+ uint8_t *buf, size_t buf_size);
+
+/*
+ * Parses a uuid string in canonical string form, outputting as an array of bytes
+ * in little endian byte order (GUID order).
+ */
+size_t uuid_parse_to_guid_octets(const char *canonical_form,
+ uint8_t *buf, size_t buf_size);
+
+/*
+ * Convert from one octet representation to the other. Works both ways.
+ */
+void uuid_reverse_octets(const struct uuid_octets *input_octets,
+ uint8_t *buf, size_t buf_size);
+
+/*
+ * Converts a valid canonical uuid string to the standard octet byte order. Should only
+ * be used if the input canonical string is trusted to be valid. Will assert if it's not.
+ */
+void uuid_octets_from_canonical(struct uuid_octets *uuid_octets,
+ const char *canonical_form);
+
+/*
+ * Converts a valid canonical uuid string to the GUID octet byte order. Should only
+ * be used if the input canonical string is trusted to be valid. Will assert if it's not.
+ */
+void uuid_guid_octets_from_canonical(struct uuid_octets *uuid_octets,
+ const char *canonical_form);
+
+/*
+ * Converts an octet representation in standard byte order to a canonical string.
*/
-size_t uuid_parse_to_octets(const char *canonical_form, uint8_t *buf, size_t buf_size);
+void uuid_canonical_from_octets(struct uuid_canonical *canonical_form,
+ const struct uuid_octets *uuid_octets);
/*
- * Parses a uuid string in canonical string form but instead of outputting octets
- * in standard byte order, octets from each section of the canonical uuid are
- * reversed.
+ * Converts an octet representation in GUID byte order to a canonical string.
*/
-size_t uuid_parse_to_octets_reversed(const char *canonical_form, uint8_t *buf, size_t buf_size);
+void uuid_canonical_from_guid_octets(struct uuid_canonical *canonical_form,
+ const struct uuid_octets *uuid_octets);
#ifdef __cplusplus
}
#endif
-#endif /* UUID_H */
+#endif /* COMMON_UUID_H */
diff --git a/components/config/interface/config_store.h b/components/config/interface/config_store.h
index 63f928267..25744cfc8 100644
--- a/components/config/interface/config_store.h
+++ b/components/config/interface/config_store.h
@@ -34,6 +34,9 @@ enum config_classifier
/* A classifier for a memory region that describes a region of memory */
CONFIG_CLASSIFIER_MEMORY_REGION,
+ /* A classifier to describe a hardware feature's availability */
+ CONFIG_CLASSIFIER_HW_FEATURE,
+
/* A classifier for an opaque configuration blob */
CONFIG_CLASSIFIER_BLOB
};
diff --git a/components/config/loader/sp/sp_config_loader.c b/components/config/loader/sp/sp_config_loader.c
index fd052f40a..5c7c55247 100644
--- a/components/config/loader/sp/sp_config_loader.c
+++ b/components/config/loader/sp/sp_config_loader.c
@@ -1,15 +1,25 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
-#include <string.h>
+#include <common/fdt/fdt_helpers.h>
#include <config/interface/config_store.h>
#include <config/interface/config_blob.h>
#include <platform/interface/device_region.h>
-#include "platform/interface/memory_region.h"
+#include <platform/interface/memory_region.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <trace.h>
+
#include "sp_config_loader.h"
+/*
+ * According to the FF-A spec: in the SP manifest the size of device and
+ * memory regions is expressed as a count of 4K pages.
+ */
+#define FFA_SP_MANIFEST_PAGE_SIZE UINT32_C(0x1000)
struct sp_param_region {
char name[16];
@@ -17,37 +27,7 @@ struct sp_param_region {
size_t size;
};
-static void load_device_regions(const struct ffa_name_value_pair *value_pair);
-static void load_memory_regions(const struct ffa_name_value_pair *value_pair);
-static void load_blob(const struct ffa_name_value_pair *value_pair);
-
-/**
- * Loads externally provided configuration data passed into the SP via
- * FFA initialisation parameters. Data can originate from
- * the SP manifest, an external device tree or a dynamic configuration
- * mechanism such as a handover block (HOB).
- */
-void sp_config_load(struct ffa_init_info *init_info)
-{
- /* Load deployment specific configuration */
- for (size_t param_index = 0; param_index < init_info->count; param_index++) {
-
- if (!strcmp((const char *)init_info->nvp[param_index].name,"DEVICE_REGIONS")) {
-
- load_device_regions(&init_info->nvp[param_index]);
- }
- else if (!strcmp((const char *)init_info->nvp[param_index].name,"MEMORY_REGIONS")) {
-
- load_memory_regions(&init_info->nvp[param_index]);
- }
- else {
-
- load_blob(&init_info->nvp[param_index]);
- }
- }
-}
-
-static void load_device_regions(const struct ffa_name_value_pair *value_pair)
+static bool load_device_regions(const struct ffa_name_value_pair_v1_0 *value_pair)
{
struct sp_param_region *d = (struct sp_param_region *)value_pair->value;
@@ -56,20 +36,27 @@ static void load_device_regions(const struct ffa_name_value_pair *value_pair)
struct device_region device_region;
- strcpy(device_region.dev_class, d->name);
+ strncpy(device_region.dev_class, d->name,
+ sizeof(device_region.dev_class));
device_region.dev_instance = 0;
device_region.base_addr = d->location;
device_region.io_region_size = d->size;
- config_store_add(CONFIG_CLASSIFIER_DEVICE_REGION,
- device_region.dev_class, device_region.dev_instance,
- &device_region, sizeof(device_region));
+ if (!config_store_add(CONFIG_CLASSIFIER_DEVICE_REGION,
+ device_region.dev_class,
+ device_region.dev_instance,
+ &device_region, sizeof(device_region))) {
+ EMSG("failed to add device region to config store");
+ return false;
+ }
++d;
}
+
+ return true;
}
-static void load_memory_regions(const struct ffa_name_value_pair *value_pair)
+static bool load_memory_regions(const struct ffa_name_value_pair_v1_0 *value_pair)
{
struct sp_param_region *d = (struct sp_param_region *)value_pair->value;
@@ -78,26 +65,300 @@ static void load_memory_regions(const struct ffa_name_value_pair *value_pair)
struct memory_region memory_region;
- strcpy(memory_region.region_name, d->name);
+ strncpy(memory_region.region_name, d->name,
+ sizeof(memory_region.region_name));
memory_region.base_addr = d->location;
memory_region.region_size = d->size;
- config_store_add(CONFIG_CLASSIFIER_MEMORY_REGION,
- memory_region.region_name, 0,
- &memory_region, sizeof(memory_region));
+ if (!config_store_add(CONFIG_CLASSIFIER_MEMORY_REGION,
+ memory_region.region_name, 0,
+ &memory_region, sizeof(memory_region))) {
+ EMSG("failed to add memory region to config store");
+ return false;
+ }
++d;
}
+
+ return true;
}
-static void load_blob(const struct ffa_name_value_pair *value_pair)
+static bool load_blob(const struct ffa_name_value_pair_v1_0 *value_pair)
{
struct config_blob blob;
blob.data = (const void*)value_pair->value;
blob.data_len = value_pair->size;
- config_store_add(CONFIG_CLASSIFIER_BLOB,
- (const char *)value_pair->name, 0,
- &blob, sizeof(blob));
+ if (!config_store_add(CONFIG_CLASSIFIER_BLOB, (const char *)value_pair->name, 0,
+ &blob, sizeof(blob))) {
+ EMSG("failed to add blob to config store");
+ return false;
+ }
+
+ return true;
+}
+
+static bool load_fdt(const void *fdt, size_t fdt_size)
+{
+ int root = -1, node = -1, subnode = -1, rc = -1;
+ static const char *ffa_manifest_compatible = "arm,ffa-manifest-1.0";
+
+ /* Sanity check */
+ if (!fdt) {
+ EMSG("fdt NULL pointer");
+ return false;
+ }
+
+ rc = fdt_check_full(fdt, fdt_size);
+ if (rc) {
+ EMSG("fdt_check_full(): %d", rc);
+ return false;
+ }
+
+ /* Find root node */
+ root = fdt_path_offset(fdt, "/");
+ if (root < 0) {
+ EMSG("fdt_path_offset(): %d", root);
+ return false;
+ }
+
+ /* Check if it's a valid SP manifest */
+ rc = fdt_node_check_compatible(fdt, root, ffa_manifest_compatible);
+ if (rc) {
+ EMSG("fdt_node_check_compatible(%s): %d", ffa_manifest_compatible, rc);
+ return false;
+ }
+
+ /* Find memory regions */
+ node = fdt_node_offset_by_compatible(fdt, root, "arm,ffa-manifest-memory-regions");
+ if (node >= 0) {
+ fdt_for_each_subnode(subnode, fdt, node) {
+ struct memory_region memory_region = {0};
+ uint64_t base_addr = 0;
+ uint32_t page_cnt = 0;
+ const char *subnode_name = fdt_get_name(fdt, subnode, NULL);
+
+ if (!subnode_name) {
+ EMSG("subnode name is missing");
+ return false;
+ }
+
+ if(!dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
+ EMSG("base-address is missing");
+ return false;
+ }
+
+ if(!dt_get_u32(fdt, subnode, "pages-count", &page_cnt)) {
+ EMSG("pages-count is missing");
+ return false;
+ }
+
+ strncpy(memory_region.region_name, subnode_name,
+ sizeof(memory_region.region_name));
+ memory_region.base_addr = (uintptr_t)base_addr;
+ memory_region.region_size = page_cnt * FFA_SP_MANIFEST_PAGE_SIZE;
+
+ if (!config_store_add(CONFIG_CLASSIFIER_MEMORY_REGION,
+ memory_region.region_name, 0,
+ &memory_region, sizeof(memory_region))) {
+ EMSG("failed to add memory region to config store");
+ return false;
+ }
+ }
+ }
+
+ /* Find device regions */
+ node = fdt_node_offset_by_compatible(fdt, root, "arm,ffa-manifest-device-regions");
+ if (node >= 0) {
+ fdt_for_each_subnode(subnode, fdt, node) {
+ struct device_region device_region = {0};
+ uint64_t base_addr = 0;
+ uint32_t page_cnt = 0;
+ const char *subnode_name = fdt_get_name(fdt, subnode, NULL);
+
+ if (!subnode_name) {
+ EMSG("subnode name is missing");
+ return false;
+ }
+
+ if(!dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
+ EMSG("base-address is missing");
+ return false;
+ }
+
+ if (!dt_get_u32(fdt, subnode, "pages-count", &page_cnt)) {
+ EMSG("pages-count is missing");
+ return false;
+ }
+
+ strncpy(device_region.dev_class, subnode_name,
+ sizeof(device_region.dev_class));
+ device_region.base_addr = base_addr;
+ device_region.io_region_size = page_cnt * FFA_SP_MANIFEST_PAGE_SIZE;
+ device_region.dev_instance = 0;
+
+ if (!config_store_add(CONFIG_CLASSIFIER_DEVICE_REGION,
+ device_region.dev_class, device_region.dev_instance,
+ &device_region, sizeof(device_region))) {
+ EMSG("failed to add device region to config store");
+ return false;
+ }
+ }
+ }
+
+ /* Find TPM event log */
+ node = fdt_node_offset_by_compatible(fdt, root, "arm,tpm_event_log");
+ if (node >= 0) {
+ uint64_t tpm_event_log_addr = 0;
+ uint32_t tpm_event_log_size = 0;
+ struct config_blob blob = { 0 };
+
+ if (!dt_get_u64(fdt, node, "tpm_event_log_addr", &tpm_event_log_addr)) {
+ EMSG("tpm_event_log_addr is missing");
+ return false;
+ }
+
+ if (!dt_get_u32(fdt, node, "tpm_event_log_size", &tpm_event_log_size)) {
+ EMSG("tpm_event_log_size is missing");
+ return false;
+ }
+
+ blob.data = (const void *)tpm_event_log_addr;
+ blob.data_len = tpm_event_log_size;
+
+ if (!config_store_add(CONFIG_CLASSIFIER_BLOB, "EVENT_LOG", 0,
+ (void *)&blob, sizeof(blob))) {
+ EMSG("failed to add event log to config store");
+ return false;
+ }
+ }
+
+ /* Find hardware features */
+ node = fdt_node_offset_by_compatible(fdt, root, "arm,hw-features");
+ if (node >= 0) {
+ const char *prop_name = NULL;
+ uint32_t prop_value = 0;
+ int prop_offset = 0;
+
+ fdt_for_each_property_offset(prop_offset, fdt, node) {
+ if (!dt_get_u32_by_offset(fdt, prop_offset, &prop_name, &prop_value)) {
+ /* skip other properties in the node, e.g. the compatible string */
+ DMSG("skipping non-u32 property '%s' in hw-features", prop_name);
+ continue;
+ }
+
+ if (!config_store_add(CONFIG_CLASSIFIER_HW_FEATURE, prop_name, 0,
+ &prop_value, sizeof(prop_value))) {
+ EMSG("failed to add HW feature to config store");
+ return false;
+ }
+ }
+ } else {
+ DMSG("arm,hw-features node not present in SP manifest");
+ }
+
+ return true;
+}
+
+static bool sp_config_load_v1_0(struct ffa_boot_info_v1_0 *boot_info)
+{
+ /* Load deployment specific configuration */
+ for (size_t param_index = 0; param_index < boot_info->count; param_index++) {
+ const char *name = (const char *)boot_info->nvp[param_index].name;
+ const size_t name_max_size = sizeof(boot_info->nvp[param_index].name);
+
+ if (!strncmp(name, "DEVICE_REGIONS", name_max_size)) {
+ if (!load_device_regions(&boot_info->nvp[param_index])) {
+ EMSG("Failed to load device regions");
+ return false;
+ }
+ } else if (!strncmp(name, "MEMORY_REGIONS", name_max_size)) {
+ if (!load_memory_regions(&boot_info->nvp[param_index])) {
+ EMSG("Failed to load memory regions");
+ return false;
+ }
+ } else if (!memcmp(name, "TYPE_DT\0\0\0\0\0\0\0\0", name_max_size)) {
+ if (!load_fdt((void *)boot_info->nvp[param_index].value,
+ boot_info->nvp[param_index].size)) {
+ EMSG("Failed to load SP config from DT");
+ return false;
+ }
+ } else {
+ if (!load_blob(&boot_info->nvp[param_index])) {
+ EMSG("Failed to load blob");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool sp_config_load_v1_1(struct ffa_boot_info_header_v1_1 *boot_info_header)
+{
+ size_t desc_end = 0;
+ size_t total_desc_size = 0;
+ struct ffa_boot_info_desc_v1_1 *boot_info_desc = NULL;
+ uint32_t expected_version = SHIFT_U32(1, FFA_VERSION_MAJOR_SHIFT) |
+ SHIFT_U32(1, FFA_VERSION_MINOR_SHIFT);
+
+ if (boot_info_header->version != expected_version) {
+ EMSG("Invalid FF-A boot info version");
+ return false;
+ }
+
+ if (boot_info_header->desc_size != sizeof(struct ffa_boot_info_desc_v1_1)) {
+ EMSG("Boot info descriptor size mismatch");
+ return false;
+ }
+
+ if (MUL_OVERFLOW(boot_info_header->desc_size, boot_info_header->desc_cnt,
+ &total_desc_size)) {
+ EMSG("Boot info descriptor overflow");
+ return false;
+ }
+
+ if (ADD_OVERFLOW(boot_info_header->desc_offs, total_desc_size, &desc_end) ||
+ boot_info_header->size < desc_end) {
+ EMSG("Boot info descriptor overflow");
+ return false;
+ }
+
+ boot_info_desc = (struct ffa_boot_info_desc_v1_1 *)((uintptr_t)boot_info_header +
+ boot_info_header->desc_offs);
+
+ for (unsigned int i = 0; i < boot_info_header->desc_cnt; i++) {
+ uint16_t flags = FFA_BOOT_INFO_CONTENT_FMT_ADDR << FFA_BOOT_INFO_CONTENT_FMT_SHIFT;
+ uint16_t type = FFA_BOOT_INFO_TYPE_STD << FFA_BOOT_INFO_TYPE_SHIFT |
+ FFA_BOOT_INFO_ID_STD_FDT << FFA_BOOT_INFO_ID_SHIFT;
+
+ if (boot_info_desc[i].flags == flags && boot_info_desc[i].type == type) {
+ if (!load_fdt((void *)boot_info_desc->contents, boot_info_desc->size)) {
+ EMSG("Failed to load SP config FDT");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool sp_config_load(union ffa_boot_info *boot_info)
+{
+ if (!boot_info)
+ return false;
+
+ switch (boot_info->signature) {
+ case FFA_BOOT_INFO_SIGNATURE_V1_0:
+ return sp_config_load_v1_0((struct ffa_boot_info_v1_0 *)&boot_info->boot_info_v1_0);
+ case FFA_BOOT_INFO_SIGNATURE_V1_1:
+ return sp_config_load_v1_1((struct ffa_boot_info_header_v1_1 *)
+ &boot_info->boot_info_v1_1);
+ default:
+ EMSG("Invalid FF-A boot info signature");
+ return false;
+ }
+
+ return false;
}
diff --git a/components/config/loader/sp/sp_config_loader.h b/components/config/loader/sp/sp_config_loader.h
index a1c8bf0a1..3e585ce52 100644
--- a/components/config/loader/sp/sp_config_loader.h
+++ b/components/config/loader/sp/sp_config_loader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,12 +8,12 @@
#define SP_CONFIG_LOADER_H
#include <ffa_api.h>
+#include <stdbool.h>
/**
* Loads the secure partition specific configuration passed as
* SP initialization parameters.
*/
-void sp_config_load(struct ffa_init_info *init_info);
-
+bool sp_config_load(union ffa_boot_info *boot_info);
#endif /* SP_CONFIG_LOADER_H */
diff --git a/components/config/ramstore/config_ramstore.c b/components/config/ramstore/config_ramstore.c
index 42d749e2d..af26a57a7 100644
--- a/components/config/ramstore/config_ramstore.c
+++ b/components/config/ramstore/config_ramstore.c
@@ -1,11 +1,12 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "config_ramstore.h"
-#include <config/interface/config_store.h>
+#include "config/interface/config_store.h"
+#include "trace.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
@@ -72,7 +73,7 @@ void config_ramstore_deinit(void)
while (ramstore.object_list) {
struct config_container *next = ramstore.object_list->next;
- free(ramstore.object_list);
+ config_container_destroy(ramstore.object_list);
ramstore.object_list = next;
}
}
@@ -106,13 +107,15 @@ bool config_store_query(enum config_classifier classifier,
while (container) {
if ((container->classifier == classifier) &&
- (strcmp(container->name, name) == 0) &&
+ (strncmp(container->name, name, sizeof(container->name)) == 0) &&
(container->instance == instance)) {
if (data_buf_size == container->size) {
-
memcpy(data, config_container_data(container), container->size);
success = true;
+ } else {
+ DMSG("Query with different size (%lu != %lu)", data_buf_size,
+ container->size);
}
break;
@@ -121,6 +124,9 @@ bool config_store_query(enum config_classifier classifier,
container = container->next;
}
+ if (!success)
+ DMSG("Failed to query data with name %s", name);
+
return success;
}
diff --git a/components/config/ramstore/test/ramstore_tests.cpp b/components/config/ramstore/test/ramstore_tests.cpp
index a9cde4f0f..a357e014e 100644
--- a/components/config/ramstore/test/ramstore_tests.cpp
+++ b/components/config/ramstore/test/ramstore_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -70,8 +70,6 @@ TEST(ConfigRamstoreTests, checkSingleConfig)
TEST(ConfigRamstoreTests, checkMultipleConfig)
{
- int status;
-
/* Add first config object */
struct device_region config1;
diff --git a/components/media/disk/component.cmake b/components/media/disk/component.cmake
new file mode 100644
index 000000000..0cb3125b2
--- /dev/null
+++ b/components/media/disk/component.cmake
@@ -0,0 +1,19 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+#-------------------------------------------------------------------------------
+# Depends on the tf-a external component
+#-------------------------------------------------------------------------------
+set(_DISK_UEFI_DIR "${TFA_SOURCE_DIR}/drivers/partition")
+
+target_sources(${TGT} PRIVATE
+ "${_DISK_UEFI_DIR}/gpt.c"
+ "${_DISK_UEFI_DIR}/partition.c"
+) \ No newline at end of file
diff --git a/components/media/disk/disk_images/component.cmake b/components/media/disk/disk_images/component.cmake
new file mode 100644
index 000000000..5e4538c57
--- /dev/null
+++ b/components/media/disk/disk_images/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ref_partition.c"
+ )
diff --git a/components/media/disk/disk_images/multi_location_fw.img b/components/media/disk/disk_images/multi_location_fw.img
new file mode 100644
index 000000000..b26335c51
--- /dev/null
+++ b/components/media/disk/disk_images/multi_location_fw.img
Binary files differ
diff --git a/components/media/disk/disk_images/readme.rst b/components/media/disk/disk_images/readme.rst
new file mode 100644
index 000000000..0f2d2c013
--- /dev/null
+++ b/components/media/disk/disk_images/readme.rst
@@ -0,0 +1,75 @@
+UEFI disk image creation instructions
+=====================================
+
+This directory contains a set of UEFI disk images, formatted with a
+protective MBR and GPT. The images are intended for test purposes.
+For convenience, there is a C version of the disk image that can be
+built into test deployments.
+
+Once the MBR and GPT have been added, for a sector size of 512 bytes,
+the first usable LBA is 34. 34 free blocks are also needed at the top
+of the LBA space to accommodate theh backup MBR and GPT.
+
+Tools used to create images were:
+
+ - gdisk
+ - sgdisk
+ - srec_cat (to generate C from binary image - http://srecord.sourceforge.net/)
+
+Steps to create:
+
+ 1. Create a file to represent an empty flash device. All data set to
+ 0xff (the normal erased value). Use ('bs' is block size, 'count' is
+ number of blocks)::
+
+ dd if=/dev/zero bs=512 count=267 | tr "\000" "\377" >flash.img
+
+ 2. Create MBR+GPT using::
+
+ # -N 1 - create partition 1 with max available size
+ # -c 1:<name> Set the name of partition 1
+ # -u 1:<GUID>> #set the uniq GUID
+ sgdisk -N 1 -c 1:"PARTITION_1" -u 1:92f7d53b-127e-432b-815c-9a95b80d69b7 flash.img
+
+ or alternatively run the interative ``gdisk`` tool::
+
+ gdisk flash.img
+ use 'n' command to add partitions
+ use 'c' to define partition names
+ use 'x' to allow extra functionality
+ use 'c' to change partition GUID (see value above)
+ use 'm' to return to normal mode
+ use 'w' to save to file
+
+ 3. Convert the disk to C code::
+
+ srec_cat flash.img -Binary -o ref_partition_data.c -C-Array ref_partition_data -INClude
+
+Disk Image Descriptions
+-----------------------
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - Image file
+ - Description
+ * - components/media/disk/disk_images/ref_partition.img
+ - Block storage tests assume a reference partition configuration consisting of a set of four
+ partitions of varying size. This is a UEFI disk image where two of the partitions are big
+ enough for providing backend storage for the Internal Trusted Storage and Protected Storage
+ services, at least from a TS test perspective.
+ * - components/media/disk/disk_images/single_location_fw.img
+ - This UEFI disk image contains the set of partitions you'd expect to find in flash for a
+ device where firmware is stored in a single A/B pair of partitions.
+ * - components/media/disk/disk_images/multi_location_fw.img
+ - This UEFI disk image contains the set of partitions you'd expect to find in flash for a
+ device where firmware is distributed across multiple locations. In this case, there are
+ locations for AP firmware, SCP firmware and RSS firmware.
+
+
+--------------
+
+*Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/components/media/disk/disk_images/ref_partition.c b/components/media/disk/disk_images/ref_partition.c
new file mode 100644
index 000000000..1d17221cd
--- /dev/null
+++ b/components/media/disk/disk_images/ref_partition.c
@@ -0,0 +1,11416 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/**
+ * Data for a disk image formatted with MBR+GPT with 4 partitions with
+ * the same layout as the reference partition configuration used for
+ * block_storage testing (see: components/service/block_storage/config/ref).
+ */
+const unsigned char ref_partition_data[] =
+{
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xEE, 0x04, 0x0F, 0x00, 0x01, 0x00,
+0x00, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA, 0x45, 0x46, 0x49, 0x20,
+0x50, 0x41, 0x52, 0x54, 0x00, 0x00, 0x01, 0x00, 0x5C, 0x00, 0x00, 0x00,
+0x62, 0x79, 0xFA, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xA5, 0x63, 0x3B, 0x1E, 0xC7, 0xF9, 0xB7, 0x4D,
+0x9B, 0xB1, 0xD2, 0x83, 0x2B, 0x3D, 0xD7, 0x2F, 0x02, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+0xA3, 0x98, 0xC0, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47,
+0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4, 0x3B, 0xD5, 0xF7, 0x92,
+0x7E, 0x12, 0x2B, 0x43, 0x81, 0x5C, 0x9A, 0x95, 0xB8, 0x0D, 0x69, 0xB7,
+0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x54, 0x00, 0x49, 0x00, 0x54, 0x00,
+0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00, 0x31, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69,
+0xD8, 0x47, 0x7D, 0xE4, 0xDA, 0x56, 0x14, 0x70, 0x50, 0x9B, 0xB2, 0x49,
+0x97, 0x22, 0x47, 0x51, 0x0F, 0x85, 0x1C, 0xCD, 0x82, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x41, 0x00,
+0x52, 0x00, 0x54, 0x00, 0x49, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00,
+0x4E, 0x00, 0x5F, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x3D, 0xC6, 0x0F,
+0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4,
+0xA6, 0xF8, 0x9E, 0xC3, 0x97, 0xEC, 0x83, 0x48, 0xAA, 0x64, 0x02, 0x5F,
+0x40, 0xF7, 0xD9, 0x22, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x54, 0x00,
+0x49, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00,
+0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47,
+0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4, 0x65, 0x20, 0xD8, 0xC3,
+0xF3, 0x58, 0xCB, 0x4F, 0xA8, 0xFC, 0x77, 0x24, 0x34, 0xBF, 0xC9, 0x1D,
+0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x54, 0x00, 0x49, 0x00, 0x54, 0x00,
+0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00, 0x34, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69,
+0xD8, 0x47, 0x7D, 0xE4, 0x3B, 0xD5, 0xF7, 0x92, 0x7E, 0x12, 0x2B, 0x43,
+0x81, 0x5C, 0x9A, 0x95, 0xB8, 0x0D, 0x69, 0xB7, 0x22, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x41, 0x00,
+0x52, 0x00, 0x54, 0x00, 0x49, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00,
+0x4E, 0x00, 0x5F, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x3D, 0xC6, 0x0F,
+0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4,
+0xDA, 0x56, 0x14, 0x70, 0x50, 0x9B, 0xB2, 0x49, 0x97, 0x22, 0x47, 0x51,
+0x0F, 0x85, 0x1C, 0xCD, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x54, 0x00,
+0x49, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00,
+0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47,
+0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4, 0xA6, 0xF8, 0x9E, 0xC3,
+0x97, 0xEC, 0x83, 0x48, 0xAA, 0x64, 0x02, 0x5F, 0x40, 0xF7, 0xD9, 0x22,
+0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x54, 0x00, 0x49, 0x00, 0x54, 0x00,
+0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00, 0x33, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69,
+0xD8, 0x47, 0x7D, 0xE4, 0x65, 0x20, 0xD8, 0xC3, 0xF3, 0x58, 0xCB, 0x4F,
+0xA8, 0xFC, 0x77, 0x24, 0x34, 0xBF, 0xC9, 0x1D, 0xE6, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x41, 0x00,
+0x52, 0x00, 0x54, 0x00, 0x49, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00,
+0x4E, 0x00, 0x5F, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54,
+0x00, 0x00, 0x01, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x51, 0x65, 0xBD, 0xE9,
+0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xA5, 0x63, 0x3B, 0x1E, 0xC7, 0xF9, 0xB7, 0x4D, 0x9B, 0xB1, 0xD2, 0x83,
+0x2B, 0x3D, 0xD7, 0x2F, 0xEA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xA3, 0x98, 0xC0, 0x24,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+const unsigned long ref_partition_data_termination = 0x00000000;
+const unsigned long ref_partition_data_start = 0x00000000;
+const unsigned long ref_partition_data_finish = 0x00021600;
+const unsigned long ref_partition_data_length = 0x00021600;
+
+#define REF_PARTITION_DATA_TERMINATION 0x00000000
+#define REF_PARTITION_DATA_START 0x00000000
+#define REF_PARTITION_DATA_FINISH 0x00021600
+#define REF_PARTITION_DATA_LENGTH 0x00021600
diff --git a/components/media/disk/disk_images/ref_partition.h b/components/media/disk/disk_images/ref_partition.h
new file mode 100644
index 000000000..0a22a5095
--- /dev/null
+++ b/components/media/disk/disk_images/ref_partition.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef REF_PARTITION_DATA_H
+#define REF_PARTITION_DATA_H
+
+extern const unsigned long ref_partition_data_termination;
+extern const unsigned long ref_partition_data_start;
+extern const unsigned long ref_partition_data_finish;
+extern const unsigned long ref_partition_data_length;
+extern const unsigned char ref_partition_data[];
+
+#endif /* REF_PARTITION_DATA_H */
diff --git a/components/media/disk/disk_images/ref_partition.img b/components/media/disk/disk_images/ref_partition.img
new file mode 100644
index 000000000..4858ecf83
--- /dev/null
+++ b/components/media/disk/disk_images/ref_partition.img
Binary files differ
diff --git a/components/media/disk/disk_images/single_location_fw.img b/components/media/disk/disk_images/single_location_fw.img
new file mode 100644
index 000000000..a79294571
--- /dev/null
+++ b/components/media/disk/disk_images/single_location_fw.img
Binary files differ
diff --git a/components/media/disk/formatter/component.cmake b/components/media/disk/formatter/component.cmake
new file mode 100644
index 000000000..27b1110d2
--- /dev/null
+++ b/components/media/disk/formatter/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/disk_formatter.c"
+) \ No newline at end of file
diff --git a/components/media/disk/formatter/disk_formatter.c b/components/media/disk/formatter/disk_formatter.c
new file mode 100644
index 000000000..1d8e2fe5f
--- /dev/null
+++ b/components/media/disk/formatter/disk_formatter.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <media/volume/index/volume_index.h>
+#include <media/volume/base_io_dev/base_io_dev.h>
+#include "disk_formatter.h"
+
+int disk_formatter_clone(
+ uintptr_t dev_handle,
+ uintptr_t io_spec,
+ const uint8_t *source_image,
+ size_t source_image_size)
+{
+ uintptr_t volume_handle;
+ int result;
+
+ result = io_open(dev_handle, io_spec, &volume_handle);
+ if (result != 0)
+ return result;
+
+ result = io_seek(volume_handle, IO_SEEK_SET, 0);
+
+ if (result == 0) {
+
+ size_t length_written = 0;
+
+ result = io_write(volume_handle,
+ (const uintptr_t)source_image,
+ source_image_size,
+ &length_written);
+ }
+
+ io_close(volume_handle);
+ return result;
+} \ No newline at end of file
diff --git a/components/media/disk/formatter/disk_formatter.h b/components/media/disk/formatter/disk_formatter.h
new file mode 100644
index 000000000..e461d9aad
--- /dev/null
+++ b/components/media/disk/formatter/disk_formatter.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_DISK_FORMATTER_H
+#define MEDIA_DISK_FORMATTER_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Format a storage volume by cloning a disk image
+ *
+ * @param[in] dev_handle IO device handle
+ * @param[in] io_spec Opaque volume spec
+ * @param[in] source_image The source disk image to clone
+ * @param[in] source_image_size The size of the source image
+ *
+ * @return 0 on success
+ */
+int disk_formatter_clone(
+ uintptr_t dev_handle,
+ uintptr_t io_spec,
+ const uint8_t *source_image,
+ size_t source_image_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_DISK_FORMATTER_H */
diff --git a/components/media/disk/gpt_iterator/component.cmake b/components/media/disk/gpt_iterator/component.cmake
new file mode 100644
index 000000000..a2f74c88f
--- /dev/null
+++ b/components/media/disk/gpt_iterator/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/gpt_iterator.c"
+) \ No newline at end of file
diff --git a/components/media/disk/gpt_iterator/gpt_iterator.c b/components/media/disk/gpt_iterator/gpt_iterator.c
new file mode 100644
index 000000000..1c5ba0f1f
--- /dev/null
+++ b/components/media/disk/gpt_iterator/gpt_iterator.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "gpt_iterator.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "media/volume/volume.h"
+
+int gpt_iterator_init(struct gpt_iterator *iter, struct volume *volume)
+{
+ assert(iter);
+ assert(volume);
+
+ iter->num_entries = 0;
+ iter->entry_size = 0;
+ iter->cur_index = 0;
+ iter->volume = NULL;
+
+ int status = volume_open(volume);
+
+ if (status)
+ return status;
+
+ iter->volume = volume;
+
+ status = volume_seek(volume, IO_SEEK_SET, GPT_HEADER_OFFSET);
+
+ if (status)
+ return status;
+
+ gpt_header_t gpt_header;
+ size_t bytes_read = 0;
+
+ status = volume_read(volume, (uintptr_t)&gpt_header, sizeof(gpt_header), &bytes_read);
+
+ if (status)
+ return status;
+
+ if (bytes_read != sizeof(gpt_header))
+ return -EIO;
+
+ /* Check that GPT header looks valid. It is assumed that the CRC will already been checked
+ * e.g. by the bootloader. The checks are intended to defend against either deliberate or
+ * accidental corruption of the header leading to use of unreasonable partition table
+ * attributes. The checks need to be tolerant to GPT version changes that result in a
+ * mismatch between this code's view of structures and the structure used when the GPT
+ * in the disk image was created. This could occur through firmware updates over the
+ * lifetime of the device. An assumption is that over time, GPT structures will only ever
+ * be extended and that all versions will share a common base structure. The check for an
+ * oversized partition entry puts a reasonable upper limit on the structure size as 2 *
+ * sizeof(gpt_entry_t). This relies on there never being a 2x size mismatch over the
+ * lifetime of the device.
+ */
+ size_t min_required_entry_size =
+ offsetof(gpt_entry_t, name) + EFI_NAMELEN * sizeof(unsigned short);
+ size_t max_expected_entry_size = sizeof(gpt_entry_t) * 2;
+
+ if ((memcmp(GPT_SIGNATURE, gpt_header.signature, sizeof(gpt_header.signature)) != 0) ||
+ gpt_header.part_size < min_required_entry_size ||
+ gpt_header.part_size > max_expected_entry_size || iter->num_entries > 128)
+ return -EIO;
+
+ iter->num_entries = gpt_header.list_num;
+ iter->entry_size = gpt_header.part_size;
+
+ return 0;
+}
+
+void gpt_iterator_deinit(struct gpt_iterator *iter)
+{
+ assert(iter);
+
+ if (iter->volume)
+ volume_close(iter->volume);
+}
+
+void gpt_iterator_first(struct gpt_iterator *iter)
+{
+ assert(iter);
+
+ iter->cur_index = 0;
+}
+
+void gpt_iterator_next(struct gpt_iterator *iter)
+{
+ assert(iter);
+
+ ++iter->cur_index;
+}
+
+bool gpt_iterator_is_done(const struct gpt_iterator *iter)
+{
+ assert(iter);
+
+ return (iter->cur_index >= iter->num_entries);
+}
+
+int gpt_iterator_current(struct gpt_iterator *iter, gpt_entry_t *entry)
+{
+ assert(iter);
+ assert(iter->volume);
+ assert(!gpt_iterator_is_done(iter));
+
+ size_t bytes_read = 0;
+ size_t cur_pos = iter->cur_index * iter->entry_size + GPT_ENTRY_OFFSET;
+ int status = volume_seek(iter->volume, IO_SEEK_SET, cur_pos);
+
+ if (status)
+ return status;
+
+ status = volume_read(iter->volume, (uintptr_t)entry, sizeof(gpt_entry_t), &bytes_read);
+
+ if (status)
+ return status;
+
+ if (bytes_read != sizeof(gpt_entry_t))
+ return -EIO;
+
+ return 0;
+}
diff --git a/components/media/disk/gpt_iterator/gpt_iterator.h b/components/media/disk/gpt_iterator/gpt_iterator.h
new file mode 100644
index 000000000..b32be18ad
--- /dev/null
+++ b/components/media/disk/gpt_iterator/gpt_iterator.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef GPT_ITERATOR_H
+#define GPT_ITERATOR_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//This seems to be missing from TF-A:tf-a-src/include/tools_share/uuid.h
+#include <stdint.h>
+/**
+ * Export tf-a version with C++ linkage support.
+ */
+#include <drivers/partition/gpt.h>
+
+/**
+ * Interface dependencies
+ */
+struct volume;
+
+/**
+ * \brief gpt_iterator structure definition
+ *
+ * Holds state while iterating over partition table entries
+ */
+struct gpt_iterator {
+ unsigned int num_entries;
+ unsigned int entry_size;
+ unsigned int cur_index;
+
+ struct volume *volume;
+};
+
+/**
+ * \brief Initialize the iterator
+ *
+ * Initializes a gpt_iterator in preparation for use. The provided volume
+ * should provide access to the storage device/partition that contains the
+ * MBR/GPT at the start of the volume. The integrity of the GPT should have
+ * already been verified before using this iterator. The volume must be
+ * initially closed. It will be opened on init and closed on deinit.
+ *
+ * \param[in] iter The subject gpt_iterator
+ * \param[in] volume Volume containing the MBR/GPT
+ *
+ * \return IO Status code (0 for success)
+ */
+int gpt_iterator_init(struct gpt_iterator *iter, struct volume *volume);
+
+/**
+ * \brief De-initialize the iterator
+ *
+ * \param[in] iter The subject gpt_iterator
+ */
+void gpt_iterator_deinit(struct gpt_iterator *iter);
+
+/**
+ * \brief Set iterator position to first partition entry
+ *
+ * \param[in] iter The subject gpt_iterator
+ */
+void gpt_iterator_first(struct gpt_iterator *iter);
+
+/**
+ * \brief Iterate to the next entry
+ *
+ * \param[in] iter The subject gpt_iterator
+ */
+void gpt_iterator_next(struct gpt_iterator *iter);
+
+/**
+ * \brief Returns true if iterated beyond final entry
+ *
+ * \param[in] iter The subject gpt_iterator
+ */
+bool gpt_iterator_is_done(const struct gpt_iterator *iter);
+
+/**
+ * \brief Returns the partition entry at the current iterator position
+ *
+ * \param[in] iter The subject gpt_iterator
+ * \param[out] entry Copied to this structure
+ *
+ * \return IO Status code (0 for success)
+ */
+int gpt_iterator_current(struct gpt_iterator *iter, gpt_entry_t *entry);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GPT_ITERATOR_H */
diff --git a/components/media/disk/guid.h b/components/media/disk/guid.h
new file mode 100644
index 000000000..6968708c4
--- /dev/null
+++ b/components/media/disk/guid.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_DISK_GUID_H
+#define MEDIA_DISK_GUID_H
+
+/**
+ * Some common GUID definitions related to disk object identification used
+ * by TS components. This is not intended to be a comprehensive list. Platform
+ * integrators are free to define their own GUIDs and to manage them externally.
+ */
+
+/* Partition type GUIDs */
+#define DISK_GUID_PARTITION_TYPE_FWU_METADATA \
+ "8a7a84a0-8387-40f6-ab41-a8b9a5a60d23"
+
+#define DISK_GUID_PARTITION_TYPE_SFS_STORAGE \
+ "a495f487-892c-4d9d-b5dc-679a10985aed"
+
+/* Unique partition GUIDs */
+#define DISK_GUID_UNIQUE_PARTITION_PRIMARY_FWU_METADATA \
+ "c39ef8a6-ec97-4883-aa64-025f40f7d922"
+
+#define DISK_GUID_UNIQUE_PARTITION_BACKUP_FWU_METADATA \
+ "c3d82065-58f3-4fcb-a8fc-772434bfc91d"
+
+#define DISK_GUID_UNIQUE_PARTITION_PSA_ITS \
+ "92f7d53b-127e-432b-815c-9a95b80d69b7"
+
+#define DISK_GUID_UNIQUE_PARTITION_PSA_PS \
+ "701456da-9b50-49b2-9722-47510f851ccd"
+
+#define DISK_GUID_UNIQUE_PARTITION_DISK_HEADER \
+ "5cb130b7-a138-4d08-b0be-c2d4eff57870"
+
+#define DISK_GUID_UNIQUE_PARTITION_BOOT_BANK_A \
+ "27365ff7-90fe-410b-9fb8-4595fdc27867"
+
+#define DISK_GUID_UNIQUE_PARTITION_BOOT_BANK_B \
+ "3a87713e-4b0b-4361-b6d4-019f0ccfe41a"
+
+#endif /* MEDIA_DISK_GUID_H */
diff --git a/components/media/disk/partition_table.h b/components/media/disk/partition_table.h
new file mode 100644
index 000000000..d79018b31
--- /dev/null
+++ b/components/media/disk/partition_table.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_DISK_PARTITION_TABLE_H
+#define MEDIA_DISK_PARTITION_TABLE_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Export tf-a version with C++ linkage support.
+ */
+#include <drivers/partition/gpt.h>
+#include <drivers/partition/partition.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_DISK_PARTITION_TABLE_H */
diff --git a/components/media/disk/test/component.cmake b/components/media/disk/test/component.cmake
new file mode 100644
index 000000000..993ac942c
--- /dev/null
+++ b/components/media/disk/test/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/gpt_iterator_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/partition_table_tests.cpp"
+ )
diff --git a/components/media/disk/test/gpt_iterator_tests.cpp b/components/media/disk/test/gpt_iterator_tests.cpp
new file mode 100644
index 000000000..b7d4d26db
--- /dev/null
+++ b/components/media/disk/test/gpt_iterator_tests.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <cstring>
+#include <string>
+
+#include "common/uuid/uuid.h"
+#include "media/disk/gpt_iterator/gpt_iterator.h"
+#include "media/disk/guid.h"
+#include "media/volume/block_volume/block_volume.h"
+#include "media/volume/index/volume_index.h"
+#include "service/block_storage/config/ref/ref_partition_configurator.h"
+#include "service/block_storage/factory/ref_ram_gpt/block_store_factory.h"
+
+TEST_GROUP(GptIteratorTests)
+{
+ void setup()
+ {
+ volume_index_init();
+
+ /* Create GPT configured block_store using ref partition configuration */
+ m_block_store = ref_ram_gpt_block_store_factory_create();
+ CHECK_TRUE(m_block_store);
+
+ /* Use partition exposed for accessing the disk header */
+ uuid_guid_octets_from_canonical(&m_partition_guid,
+ DISK_GUID_UNIQUE_PARTITION_DISK_HEADER);
+
+ m_volume = NULL;
+
+ int status = block_volume_init(&m_block_volume, m_block_store, &m_partition_guid,
+ &m_volume);
+
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(m_volume);
+
+ status = gpt_iterator_init(&m_iter, m_volume);
+ LONGS_EQUAL(0, status);
+ }
+
+ void teardown()
+ {
+ gpt_iterator_deinit(&m_iter);
+ block_volume_deinit(&m_block_volume);
+ ref_ram_gpt_block_store_factory_destroy(m_block_store);
+ volume_index_clear();
+ }
+
+ bool check_in_use(const gpt_entry_t *entry)
+ {
+ struct uuid_octets nil_uuid;
+
+ memset(&nil_uuid, 0, sizeof(nil_uuid));
+ return (memcmp(nil_uuid.octets, &entry->type_uuid, sizeof(nil_uuid.octets)) != 0);
+ }
+
+ static const uint32_t CLIENT_ID = 0;
+ static const size_t FIRST_USABLE_LBA = 34;
+
+ struct uuid_octets m_partition_guid;
+ struct block_store *m_block_store;
+ struct block_volume m_block_volume;
+ struct volume *m_volume;
+ struct gpt_iterator m_iter;
+};
+
+TEST(GptIteratorTests, iterateOverRefGpt)
+{
+ /* Expect the reference partition configuration to contain 4 partitions */
+ struct uuid_octets guid;
+ gpt_entry_t gpt_entry;
+ int status;
+
+ /* Set iterator to first entry */
+ gpt_iterator_first(&m_iter);
+ CHECK_FALSE(gpt_iterator_is_done(&m_iter));
+
+ /* Expect to read ref partition 1 */
+ status = gpt_iterator_current(&m_iter, &gpt_entry);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(check_in_use(&gpt_entry));
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_1_GUID);
+ MEMCMP_EQUAL(guid.octets, (uint8_t *)&gpt_entry.unique_uuid, sizeof(guid.octets));
+ UNSIGNED_LONGS_EQUAL(FIRST_USABLE_LBA + REF_PARTITION_1_STARTING_LBA, gpt_entry.first_lba);
+ UNSIGNED_LONGS_EQUAL((FIRST_USABLE_LBA + REF_PARTITION_1_ENDING_LBA), gpt_entry.last_lba);
+
+ /* Iterate to next */
+ gpt_iterator_next(&m_iter);
+ CHECK_FALSE(gpt_iterator_is_done(&m_iter));
+
+ /* Expect to read ref partition 2 */
+ status = gpt_iterator_current(&m_iter, &gpt_entry);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(check_in_use(&gpt_entry));
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_2_GUID);
+ MEMCMP_EQUAL(guid.octets, (uint8_t *)&gpt_entry.unique_uuid, sizeof(guid.octets));
+ UNSIGNED_LONGS_EQUAL(FIRST_USABLE_LBA + REF_PARTITION_2_STARTING_LBA, gpt_entry.first_lba);
+ UNSIGNED_LONGS_EQUAL((FIRST_USABLE_LBA + REF_PARTITION_2_ENDING_LBA), gpt_entry.last_lba);
+
+ /* Iterate to next */
+ gpt_iterator_next(&m_iter);
+ CHECK_FALSE(gpt_iterator_is_done(&m_iter));
+
+ /* Expect to read ref partition 3 */
+ status = gpt_iterator_current(&m_iter, &gpt_entry);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(check_in_use(&gpt_entry));
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_3_GUID);
+ MEMCMP_EQUAL(guid.octets, (uint8_t *)&gpt_entry.unique_uuid, sizeof(guid.octets));
+ UNSIGNED_LONGS_EQUAL(FIRST_USABLE_LBA + REF_PARTITION_3_STARTING_LBA, gpt_entry.first_lba);
+ UNSIGNED_LONGS_EQUAL((FIRST_USABLE_LBA + REF_PARTITION_3_ENDING_LBA), gpt_entry.last_lba);
+
+ /* Iterate to next */
+ gpt_iterator_next(&m_iter);
+ CHECK_FALSE(gpt_iterator_is_done(&m_iter));
+
+ /* Expect to read ref partition 4 */
+ status = gpt_iterator_current(&m_iter, &gpt_entry);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(check_in_use(&gpt_entry));
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_4_GUID);
+ MEMCMP_EQUAL(guid.octets, (uint8_t *)&gpt_entry.unique_uuid, sizeof(guid.octets));
+ UNSIGNED_LONGS_EQUAL(FIRST_USABLE_LBA + REF_PARTITION_4_STARTING_LBA, gpt_entry.first_lba);
+ UNSIGNED_LONGS_EQUAL((FIRST_USABLE_LBA + REF_PARTITION_4_ENDING_LBA), gpt_entry.last_lba);
+
+ /* Don't expect any other entries to be in-use */
+ gpt_iterator_next(&m_iter);
+
+ while (!gpt_iterator_is_done(&m_iter)) {
+ status = gpt_iterator_current(&m_iter, &gpt_entry);
+ LONGS_EQUAL(0, status);
+ CHECK_FALSE(check_in_use(&gpt_entry));
+
+ gpt_iterator_next(&m_iter);
+ }
+}
diff --git a/components/media/disk/test/partition_table_tests.cpp b/components/media/disk/test/partition_table_tests.cpp
new file mode 100644
index 000000000..29cf0dd4d
--- /dev/null
+++ b/components/media/disk/test/partition_table_tests.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <string>
+#include <cstring>
+#include <common/uuid/uuid.h>
+#include <service/block_storage/block_store/device/ram/ram_block_store.h>
+#include <service/block_storage/config/ref/ref_partition_configurator.h>
+#include <media/volume/index/volume_index.h>
+#include <media/volume/block_volume/block_volume.h>
+#include <media/disk/disk_images/ref_partition.h>
+#include <media/disk/formatter/disk_formatter.h>
+#include <media/disk/partition_table.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(PartitionTableTests)
+{
+ void setup()
+ {
+ /* Load reference GPT image into ram block store */
+ size_t block_size = PLAT_PARTITION_BLOCK_SIZE;
+ size_t num_blocks = ref_partition_data_length / block_size;
+
+ m_block_store = ram_block_store_init(&m_ram_block_store,
+ NULL,
+ num_blocks, block_size);
+
+ CHECK_TRUE(m_block_store);
+
+ memset(m_partition_guid.octets, 0, sizeof(m_partition_guid.octets));
+
+ m_volume = NULL;
+
+ int result = block_volume_init(&m_block_volume,
+ m_block_store, &m_partition_guid,
+ &m_volume);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_volume);
+
+ result = disk_formatter_clone(
+ m_volume->dev_handle, m_volume->io_spec,
+ ref_partition_data, ref_partition_data_length);
+
+ LONGS_EQUAL(0, result);
+
+ volume_index_init();
+ volume_index_add(VOLUME_ID_SECURE_FLASH, m_volume);
+ }
+
+ void teardown()
+ {
+ block_volume_deinit(&m_block_volume);
+ ram_block_store_deinit(&m_ram_block_store);
+ volume_index_clear();
+ }
+
+ void uuid_from_canonical(uuid_t *uuid, const char *canonical)
+ {
+ uuid_parse_to_guid_octets(canonical, (uint8_t*)uuid, sizeof(uuid_t));
+ }
+
+ void corrupt_mbr()
+ {
+ /* Scribble over the protective MBR signature */
+ static const char scribble[] = "scribble";
+ psa_status_t status = ram_block_store_modify(
+ &m_ram_block_store, 510,
+ (const uint8_t*)scribble, sizeof(scribble));
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ void corrupt_primary_gpt_header()
+ {
+ /* Scribble over the primary GPT header in block 1 */
+ static const char scribble[] = "scribble";
+ psa_status_t status = ram_block_store_modify(
+ &m_ram_block_store, PLAT_PARTITION_BLOCK_SIZE * 1,
+ (const uint8_t*)scribble, sizeof(scribble));
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ static const uint32_t CLIENT_ID = 0;
+ static const size_t FIRST_USABLE_LBA = 34;
+
+ struct uuid_octets m_partition_guid;
+ struct block_store *m_block_store;
+ struct ram_block_store m_ram_block_store;
+ struct block_volume m_block_volume;
+ struct volume *m_volume;
+};
+
+TEST(PartitionTableTests, loadRefPartitionTable)
+{
+ int result = load_partition_table(VOLUME_ID_SECURE_FLASH);
+ LONGS_EQUAL(0, result);
+
+ /* Check for expected partition entries */
+ const partition_entry_t *partition_entry = NULL;
+ uuid_t partition_guid;
+
+ uuid_from_canonical(&partition_guid, REF_PARTITION_1_GUID);
+ partition_entry = get_partition_entry_by_uuid(&partition_guid);
+ CHECK_TRUE(partition_entry);
+ UNSIGNED_LONGS_EQUAL(
+ FIRST_USABLE_LBA + REF_PARTITION_1_STARTING_LBA,
+ partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
+ UNSIGNED_LONGS_EQUAL(
+ (REF_PARTITION_1_ENDING_LBA - REF_PARTITION_1_STARTING_LBA + 1),
+ partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
+
+ uuid_from_canonical(&partition_guid, REF_PARTITION_2_GUID);
+ partition_entry = get_partition_entry_by_uuid(&partition_guid);
+ CHECK_TRUE(partition_entry);
+ UNSIGNED_LONGS_EQUAL(
+ FIRST_USABLE_LBA + REF_PARTITION_2_STARTING_LBA,
+ partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
+ UNSIGNED_LONGS_EQUAL(
+ (REF_PARTITION_2_ENDING_LBA - REF_PARTITION_2_STARTING_LBA + 1),
+ partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
+
+ uuid_from_canonical(&partition_guid, REF_PARTITION_3_GUID);
+ partition_entry = get_partition_entry_by_uuid(&partition_guid);
+ CHECK_TRUE(partition_entry);
+ UNSIGNED_LONGS_EQUAL(
+ FIRST_USABLE_LBA + REF_PARTITION_3_STARTING_LBA,
+ partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
+ UNSIGNED_LONGS_EQUAL(
+ (REF_PARTITION_3_ENDING_LBA - REF_PARTITION_3_STARTING_LBA + 1),
+ partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
+
+ uuid_from_canonical(&partition_guid, REF_PARTITION_4_GUID);
+ partition_entry = get_partition_entry_by_uuid(&partition_guid);
+ CHECK_TRUE(partition_entry);
+ UNSIGNED_LONGS_EQUAL(
+ FIRST_USABLE_LBA + REF_PARTITION_4_STARTING_LBA,
+ partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
+ UNSIGNED_LONGS_EQUAL(
+ (REF_PARTITION_4_ENDING_LBA - REF_PARTITION_4_STARTING_LBA + 1),
+ partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
+}
+
+TEST(PartitionTableTests, detectCorruptedMbr)
+{
+ corrupt_mbr();
+ int result = load_partition_table(VOLUME_ID_SECURE_FLASH);
+ LONGS_EQUAL(-ENOENT, result);
+}
+
+// Shows up defect in TF-A where failed GPT header CRC results in an assert.
+IGNORE_TEST(PartitionTableTests, detectCorruptedGptHeader)
+{
+ /* Load should be successful with a corrupted primary GPT header as
+ * backup is still available.
+ */
+ corrupt_primary_gpt_header();
+ int result = load_partition_table(VOLUME_ID_SECURE_FLASH);
+ LONGS_EQUAL(0, result);
+}
diff --git a/components/media/volume/base_io_dev/base_io_dev.h b/components/media/volume/base_io_dev/base_io_dev.h
new file mode 100644
index 000000000..83fcb72a7
--- /dev/null
+++ b/components/media/volume/base_io_dev/base_io_dev.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_BASE_IO_DEV_H
+#define MEDIA_BASE_IO_DEV_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Base io_dev definition. An io_dev is a tf-a abstraction used for accessing
+ * an underlying storage volume as a single file with posix-like file I/O
+ * operations.
+ *
+ * Export tf-a version with C++ linkage support.
+ */
+#include <drivers/io/io_storage.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_BASE_IO_DEV_H */
diff --git a/components/media/volume/base_io_dev/component.cmake b/components/media/volume/base_io_dev/component.cmake
new file mode 100644
index 000000000..a14b61507
--- /dev/null
+++ b/components/media/volume/base_io_dev/component.cmake
@@ -0,0 +1,17 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+#-------------------------------------------------------------------------------
+# Depends on the tf-a external component. The base io_dev interface is realized
+# by the following tf-a files.
+#-------------------------------------------------------------------------------
+target_sources(${TGT} PRIVATE
+ "${TFA_SOURCE_DIR}/drivers/io/io_storage.c"
+) \ No newline at end of file
diff --git a/components/media/volume/block_volume/block_volume.c b/components/media/volume/block_volume/block_volume.c
new file mode 100644
index 000000000..7482fe54a
--- /dev/null
+++ b/components/media/volume/block_volume/block_volume.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <drivers/io/io_storage.h>
+#include "block_volume.h"
+
+/* Concrete io_dev interface functions */
+static io_type_t block_volume_type(
+ void);
+static int block_volume_open(
+ io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity);
+static int block_volume_close(
+ io_entity_t *entity);
+static int block_volume_seek(
+ io_entity_t *entity, int mode, signed long long offset);
+static int block_volume_size(
+ io_entity_t *entity, size_t *length);
+static int block_volume_read(
+ io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read);
+static int block_volume_write(
+ io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written);
+
+static const io_dev_funcs_t block_volume_dev_funcs = {
+ .type = block_volume_type,
+ .open = block_volume_open,
+ .seek = block_volume_seek,
+ .size = block_volume_size,
+ .read = block_volume_read,
+ .write = block_volume_write,
+ .close = block_volume_close,
+ .dev_init = NULL,
+ .dev_close = NULL
+};
+
+/* Concrete volume functions that extend the io_dev interface */
+static int block_volume_erase(
+ uintptr_t context);
+static int block_volume_get_storage_ids(
+ uintptr_t context,
+ struct uuid_octets *partition_guid,
+ struct uuid_octets *parent_guid);
+
+int block_volume_init(
+ struct block_volume *this_instance,
+ struct block_store *block_store,
+ const struct uuid_octets *partition_guid,
+ struct volume **volume)
+{
+ /* Initialize base volume structure */
+ volume_init(
+ &this_instance->base_volume,
+ &block_volume_dev_funcs,
+ (uintptr_t)this_instance);
+
+ /* Initialize block_volume specific attributes */
+ this_instance->base_volume.erase = block_volume_erase;
+ this_instance->base_volume.get_storage_ids = block_volume_get_storage_ids;
+
+ this_instance->block_store = block_store;
+ this_instance->partition_guid = *partition_guid;
+
+ this_instance->file_pos = 0;
+ this_instance->size = 0;
+ this_instance->partition_handle = 0;
+
+ this_instance->partition_info.block_size = 0;
+ this_instance->partition_info.num_blocks = 0;
+
+ *volume = &this_instance->base_volume;
+
+ return 0;
+}
+
+void block_volume_deinit(
+ struct block_volume *this_instance)
+{
+ (void)this_instance;
+}
+
+void block_volume_set_partition_guid(
+ struct block_volume *this_instance,
+ const struct uuid_octets *partition_guid)
+{
+ this_instance->partition_guid = *partition_guid;
+}
+
+static io_type_t block_volume_type(void)
+{
+ return IO_TYPE_BLOCK;
+}
+
+static int block_volume_open(
+ io_dev_info_t *dev_info,
+ const uintptr_t spec,
+ io_entity_t *entity)
+{
+ struct block_volume *this_instance = (struct block_volume *)dev_info->info;
+ psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+ psa_status = block_store_get_partition_info(this_instance->block_store,
+ &this_instance->partition_guid,
+ &this_instance->partition_info);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ this_instance->file_pos = 0;
+ this_instance->size =
+ this_instance->partition_info.block_size * this_instance->partition_info.num_blocks;
+
+ psa_status = block_store_open(this_instance->block_store, 0,
+ &this_instance->partition_guid,
+ &this_instance->partition_handle);
+
+ entity->info = (uintptr_t)this_instance;
+ }
+
+ return (psa_status == PSA_SUCCESS) ? 0 : -EPERM;
+}
+
+static int block_volume_close(
+ io_entity_t *entity)
+{
+ struct block_volume *this_instance = (struct block_volume *)entity->info;
+
+ psa_status_t psa_status = block_store_close(this_instance->block_store, 0,
+ this_instance->partition_handle);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ this_instance->file_pos = 0;
+ this_instance->size = 0;
+ }
+
+ return (psa_status == PSA_SUCCESS) ? 0 : -ENXIO;
+}
+
+static int block_volume_seek(
+ io_entity_t *entity,
+ int mode,
+ signed long long offset)
+{
+ struct block_volume *this_instance = (struct block_volume *)entity->info;
+
+ switch (mode)
+ {
+ case IO_SEEK_SET:
+ {
+ if (offset <= this_instance->size)
+ this_instance->file_pos = (size_t)offset;
+ else
+ return -EINVAL;
+ break;
+ }
+ case IO_SEEK_CUR:
+ {
+ ssize_t target_pos = this_instance->file_pos + offset;
+ if ((target_pos >= 0) && (target_pos <= this_instance->size))
+ this_instance->file_pos = (size_t)target_pos;
+ else
+ return -EINVAL;
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int block_volume_size(
+ io_entity_t *entity,
+ size_t *length)
+{
+ struct block_volume *this_instance = (struct block_volume *)entity->info;
+ *length = this_instance->size;
+ return 0;
+}
+
+static int block_volume_read(
+ io_entity_t *entity,
+ uintptr_t buffer,
+ size_t length,
+ size_t *length_read)
+{
+ struct block_volume *this_instance = (struct block_volume *)entity->info;
+ size_t bytes_read = 0;
+ *length_read = 0;
+
+ if (!this_instance->partition_info.block_size)
+ return -EIO;
+
+ while ((bytes_read < length) && (this_instance->file_pos < this_instance->size)) {
+
+ uint64_t lba = this_instance->file_pos / this_instance->partition_info.block_size;
+ size_t offset = this_instance->file_pos % this_instance->partition_info.block_size;
+
+ size_t bytes_remaining_in_block = this_instance->partition_info.block_size - offset;
+ size_t bytes_remaining_in_file = this_instance->size - this_instance->file_pos;
+
+ size_t bytes_remaining = length - bytes_read;
+ if (bytes_remaining > bytes_remaining_in_file) bytes_remaining = bytes_remaining_in_file;
+
+ size_t requested_len = (bytes_remaining < bytes_remaining_in_block) ?
+ bytes_remaining : bytes_remaining_in_block;
+ size_t actual_len = 0;
+
+ psa_status_t psa_status = block_store_read(
+ this_instance->block_store, 0,
+ this_instance->partition_handle,
+ lba, offset,
+ requested_len,
+ (uint8_t*)(buffer + bytes_read),
+ &actual_len);
+
+ if (psa_status != PSA_SUCCESS)
+ return -EIO;
+
+ bytes_read += actual_len;
+ this_instance->file_pos += actual_len;
+ }
+
+ *length_read = bytes_read;
+ return 0;
+}
+
+static int block_volume_write(
+ io_entity_t *entity,
+ const uintptr_t buffer,
+ size_t length,
+ size_t *length_written)
+{
+ struct block_volume *this_instance = (struct block_volume *)entity->info;
+ size_t bytes_written = 0;
+ *length_written = 0;
+
+ if (!this_instance->partition_info.block_size)
+ return -EIO;
+
+ while ((bytes_written < length) && (this_instance->file_pos < this_instance->size)) {
+
+ uint64_t lba = this_instance->file_pos / this_instance->partition_info.block_size;
+ size_t offset = this_instance->file_pos % this_instance->partition_info.block_size;
+
+ size_t bytes_remaining_in_block = this_instance->partition_info.block_size - offset;
+ size_t bytes_remaining_in_file = this_instance->size - this_instance->file_pos;
+
+ size_t bytes_remaining = length - bytes_written;
+ if (bytes_remaining > bytes_remaining_in_file) bytes_remaining = bytes_remaining_in_file;
+
+ size_t requested_len = (bytes_remaining < bytes_remaining_in_block) ?
+ bytes_remaining : bytes_remaining_in_block;
+ size_t actual_len = 0;
+
+ psa_status_t psa_status = block_store_write(
+ this_instance->block_store, 0,
+ this_instance->partition_handle,
+ lba, offset,
+ (uint8_t*)(buffer + bytes_written),
+ requested_len,
+ &actual_len);
+
+ if (psa_status != PSA_SUCCESS)
+ return -EIO;
+
+ bytes_written += actual_len;
+ this_instance->file_pos += actual_len;
+ }
+
+ *length_written = bytes_written;
+ return 0;
+}
+
+static int block_volume_erase(uintptr_t context)
+{
+ struct block_volume *this_instance = (struct block_volume *)context;
+
+ /* Erase the entire open partition. Note that a block_store will clip
+ * the number of blocks to erase to the size of the partition so erasing
+ * a large number of blocks is a safe way to erase the entire partition.
+ */
+ psa_status_t psa_status = block_store_erase(
+ this_instance->block_store, 0,
+ this_instance->partition_handle,
+ 0, UINT32_MAX);
+
+ if (psa_status != PSA_SUCCESS)
+ return -EIO;
+
+ return 0;
+}
+
+static int block_volume_get_storage_ids(
+ uintptr_t context,
+ struct uuid_octets *partition_guid,
+ struct uuid_octets *parent_guid)
+{
+ struct block_volume *this_instance = (struct block_volume *)context;
+ struct storage_partition_info partition_info;
+
+ psa_status_t psa_status = block_store_get_partition_info(this_instance->block_store,
+ &this_instance->partition_guid,
+ &partition_info);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ if (partition_guid)
+ *partition_guid = partition_info.partition_guid;
+
+ if (parent_guid)
+ *parent_guid = partition_info.parent_guid;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/components/media/volume/block_volume/block_volume.h b/components/media/volume/block_volume/block_volume.h
new file mode 100644
index 000000000..8d3f2c881
--- /dev/null
+++ b/components/media/volume/block_volume/block_volume.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_BLOCK_VOLUME_H
+#define MEDIA_BLOCK_VOLUME_H
+
+#include <common/uuid/uuid.h>
+#include <media/volume/volume.h>
+#include <service/block_storage/block_store/block_store.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Provides a concrete volume that presents a block storage partition
+ * as a single volume. Access to the underlying storage is handled by an associated
+ * block_store. The block_store could be any concrete block_store.
+ */
+struct block_volume {
+ struct volume base_volume;
+ size_t file_pos;
+ size_t size;
+ struct block_store *block_store;
+ struct uuid_octets partition_guid;
+ storage_partition_handle_t partition_handle;
+ struct storage_partition_info partition_info;
+};
+
+/**
+ * @brief Initialize an block_volume instance
+ *
+ * @param[in] this_instance The subject block_volume
+ * @param[in] block_store The associated block_store
+ * @param[in] partition_guid The partition GUID
+ * @param[out] volume The base volume
+ *
+ * @return 0 on success
+ */
+int block_volume_init(
+ struct block_volume *this_instance,
+ struct block_store *block_store,
+ const struct uuid_octets *partition_guid,
+ struct volume **volume);
+
+/**
+ * @brief De-initialize an block_volume instance
+ *
+ * @param[in] this_instance The subject block_volume
+ */
+void block_volume_deinit(
+ struct block_volume *this_instance);
+
+/**
+ * @brief Set the partition GUID
+ *
+ * Modifies the partition GUID. This will be used to identify the target
+ * storage partition on a subsequent call to io_dev_open.
+ *
+ * @param[in] this_instance The subject block_volume
+ * @param[in] partition_guid The partition GUID
+ */
+void block_volume_set_partition_guid(
+ struct block_volume *this_instance,
+ const struct uuid_octets *partition_guid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_BLOCK_VOLUME_H */
diff --git a/components/media/volume/block_volume/component.cmake b/components/media/volume/block_volume/component.cmake
new file mode 100644
index 000000000..cfd2c40f3
--- /dev/null
+++ b/components/media/volume/block_volume/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_volume.c"
+) \ No newline at end of file
diff --git a/components/media/volume/block_volume/test/block_volume_tests.cpp b/components/media/volume/block_volume/test/block_volume_tests.cpp
new file mode 100644
index 000000000..eda442c66
--- /dev/null
+++ b/components/media/volume/block_volume/test/block_volume_tests.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <cstring>
+#include <string>
+
+#include "common/uuid/uuid.h"
+#include "media/volume/block_volume/block_volume.h"
+#include "media/volume/index/volume_index.h"
+#include "service/block_storage/block_store/device/ram/ram_block_store.h"
+
+TEST_GROUP(BlockVolumeTests)
+{
+ void setup()
+ {
+ uuid_guid_octets_from_canonical(&m_partition_guid,
+ "6152f22b-8128-4c1f-981f-3bd279519907");
+
+ m_block_store = ram_block_store_init(&m_ram_block_store, &m_partition_guid,
+ NUM_BLOCKS, BLOCK_SIZE);
+
+ CHECK_TRUE(m_block_store);
+
+ m_volume = NULL;
+
+ int result = block_volume_init(&m_block_volume, m_block_store, &m_partition_guid,
+ &m_volume);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_volume);
+
+ volume_index_init();
+ volume_index_add(TEST_VOLUME_ID, m_volume);
+ }
+
+ void teardown()
+ {
+ block_volume_deinit(&m_block_volume);
+ ram_block_store_deinit(&m_ram_block_store);
+ volume_index_clear();
+ }
+
+ static const unsigned int TEST_VOLUME_ID = 5;
+ static const size_t NUM_BLOCKS = 100;
+ static const size_t BLOCK_SIZE = 512;
+
+ struct uuid_octets m_partition_guid;
+ struct block_store *m_block_store;
+ struct ram_block_store m_ram_block_store;
+ struct block_volume m_block_volume;
+ struct volume *m_volume;
+};
+
+TEST(BlockVolumeTests, openClose)
+{
+ /* Check the open flow used by tf-a components */
+ uintptr_t dev_handle = 0;
+ uintptr_t io_spec = 0;
+ uintptr_t file_handle = 0;
+ int result;
+
+ result = plat_get_image_source(TEST_VOLUME_ID, &dev_handle, &io_spec);
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(dev_handle);
+
+ result = io_open(dev_handle, io_spec, &file_handle);
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(file_handle);
+
+ io_close(file_handle);
+}
+
+TEST(BlockVolumeTests, readAndWrite)
+{
+ int result = volume_open(m_volume);
+ LONGS_EQUAL(0, result);
+
+ std::string message("Oh what a beautiful mornin'");
+
+ /* Ensure writes cross a block boundary */
+ size_t num_iterations = BLOCK_SIZE / message.size() + 2;
+
+ /* Write message a few times. Expect file pointer to advance on each write */
+ for (size_t i = 0; i < num_iterations; ++i) {
+ size_t len_written = 0;
+
+ result = volume_write(m_volume, (const uintptr_t)message.c_str(), message.size(),
+ &len_written);
+
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len_written);
+ }
+
+ result = volume_seek(m_volume, IO_SEEK_SET, 0);
+ LONGS_EQUAL(0, result);
+
+ /* Expect to read back the same data */
+ uint8_t read_buf[message.size()];
+
+ for (size_t i = 0; i < num_iterations; ++i) {
+ size_t len_read = 0;
+
+ memset(read_buf, 0, sizeof(read_buf));
+
+ result = volume_read(m_volume, (const uintptr_t)read_buf, sizeof(read_buf),
+ &len_read);
+
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len_read);
+ MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+ }
+
+ result = volume_close(m_volume);
+ LONGS_EQUAL(0, result);
+}
+
+TEST(BlockVolumeTests, seekAccess)
+{
+ size_t len = 0;
+
+ int result = volume_open(m_volume);
+ LONGS_EQUAL(0, result);
+
+ std::string message("Knees up Mother Brown");
+
+ /* Initially seek to an arbitrary position around the middle of the volume */
+ size_t start_pos = (NUM_BLOCKS * BLOCK_SIZE) / 2 + 27;
+
+ /* Seek and write a few times */
+ result = volume_seek(m_volume, IO_SEEK_SET, start_pos);
+ LONGS_EQUAL(0, result);
+
+ result = volume_write(m_volume, (const uintptr_t)message.c_str(), message.size(), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len);
+
+ /* Using IO_SEEK_SET, seek forward, skipping over the written message */
+ result = volume_seek(m_volume, IO_SEEK_SET, start_pos + 110);
+ LONGS_EQUAL(0, result);
+
+ result = volume_write(m_volume, (const uintptr_t)message.c_str(), message.size(), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len);
+
+ /* Using IO_SEEK_CUR, seek forward again, far enough to skip over the message */
+ result = volume_seek(m_volume, IO_SEEK_CUR, 715);
+ LONGS_EQUAL(0, result);
+
+ result = volume_write(m_volume, (const uintptr_t)message.c_str(), message.size(), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len);
+
+ /* Perform the same sequence of seeks and expect to read back intact copies of the message */
+ uint8_t read_buf[message.size()];
+
+ result = volume_seek(m_volume, IO_SEEK_SET, start_pos);
+ LONGS_EQUAL(0, result);
+
+ result = volume_read(m_volume, (uintptr_t)read_buf, sizeof(read_buf), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len);
+ MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+
+ result = volume_seek(m_volume, IO_SEEK_SET, start_pos + 110);
+ LONGS_EQUAL(0, result);
+
+ result = volume_read(m_volume, (uintptr_t)read_buf, sizeof(read_buf), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len);
+ MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+
+ result = volume_seek(m_volume, IO_SEEK_CUR, 715);
+ LONGS_EQUAL(0, result);
+
+ result = volume_read(m_volume, (uintptr_t)read_buf, sizeof(read_buf), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len);
+ MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+
+ result = volume_close(m_volume);
+ LONGS_EQUAL(0, result);
+}
+
+TEST(BlockVolumeTests, multipleImageInstall)
+{
+ /* Test that a sequence of image install operations can be applied
+ * to the same volume. Prior to performing streamed write operations to
+ * install an image, the previous content must be erased, if the backend
+ * storage requires this e.g. for NOR flash. */
+
+ struct volume *volume = NULL;
+ int result;
+
+ result = volume_index_find(TEST_VOLUME_ID, &volume);
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(volume);
+
+ for (size_t i = 0; i < 3; ++i) {
+ size_t len = 0;
+
+ /* Each iteration represents an update installation where arbitrary sized
+ * chunks are written to the storage volume. */
+ result = volume_open(volume);
+ LONGS_EQUAL(0, result);
+
+ /* Writes will only succeed if the written blocks have already been erased.
+ * By repeatedly writing to the same blocks, this test verifies that the erase
+ * must be working correctly.
+ */
+ result = volume_erase(volume);
+ LONGS_EQUAL(0, result);
+
+ std::string chunk1("The first chunk of the update image");
+ result = volume_write(volume, (const uintptr_t)chunk1.c_str(), chunk1.size(), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(chunk1.size(), len);
+
+ std::string chunk2("And the second");
+ result = volume_write(volume, (const uintptr_t)chunk2.c_str(), chunk2.size(), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(chunk2.size(), len);
+
+ std::string chunk3("The third chunk is soooooooooooooooooooooooooooo much longer");
+ result = volume_write(volume, (const uintptr_t)chunk3.c_str(), chunk3.size(), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(chunk3.size(), len);
+
+ /* Try reading it all back */
+ std::string expected_data = chunk1 + chunk2 + chunk3;
+ uint8_t read_buf[expected_data.size()];
+
+ result = volume_seek(volume, IO_SEEK_SET, 0);
+ LONGS_EQUAL(0, result);
+
+ result = volume_read(volume, (uintptr_t)read_buf, sizeof(read_buf), &len);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(expected_data.size(), len);
+ MEMCMP_EQUAL(expected_data.c_str(), read_buf, expected_data.size());
+
+ result = volume_close(volume);
+ LONGS_EQUAL(0, result);
+ }
+}
+
+TEST(BlockVolumeTests, oversizeWrite)
+{
+ int result = volume_open(m_volume);
+ LONGS_EQUAL(0, result);
+
+ size_t vol_size;
+ result = volume_size(m_volume, &vol_size);
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(vol_size > 0);
+
+ std::string message("Message to be written many many times");
+
+ /* Expect to be able write the whole message lots of times without error */
+ size_t num_whole_messages = vol_size / message.size();
+ size_t space_remaining = vol_size % message.size();
+
+ /* Expect there to be remaining bytes free at the end of the volume*/
+ CHECK_TRUE(space_remaining > 0);
+
+ for (size_t i = 0; i < num_whole_messages; ++i) {
+ size_t len_written = 0;
+
+ result = volume_write(m_volume, (const uintptr_t)message.c_str(), message.size(),
+ &len_written);
+
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len_written);
+ }
+
+ /* Writing the message one more time should exceed the volume size */
+ size_t len_written = 0;
+
+ result = volume_write(m_volume, (const uintptr_t)message.c_str(), message.size(),
+ &len_written);
+
+ LONGS_EQUAL(0, result);
+
+ /* Expect the number of bytes written gets truncated to the size limit of the volume */
+ UNSIGNED_LONGS_EQUAL(space_remaining, len_written);
+
+ result = volume_seek(m_volume, IO_SEEK_SET, 0);
+ LONGS_EQUAL(0, result);
+
+ /* Expect to read back the same number of whole messages */
+ uint8_t read_buf[message.size()];
+
+ for (size_t i = 0; i < num_whole_messages; ++i) {
+ size_t len_read = 0;
+
+ memset(read_buf, 0, sizeof(read_buf));
+
+ result = volume_read(m_volume, (const uintptr_t)read_buf, sizeof(read_buf),
+ &len_read);
+
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(message.size(), len_read);
+ MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+ }
+
+ /* Expect final read to be truncated to the end of the volume */
+ size_t len_read = 0;
+
+ memset(read_buf, 0, sizeof(read_buf));
+
+ result = volume_read(m_volume, (const uintptr_t)read_buf, sizeof(read_buf), &len_read);
+
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(space_remaining, len_read);
+ MEMCMP_EQUAL(message.c_str(), read_buf, space_remaining);
+
+ result = volume_close(m_volume);
+ LONGS_EQUAL(0, result);
+}
diff --git a/components/media/volume/block_volume/test/component.cmake b/components/media/volume/block_volume/test/component.cmake
new file mode 100644
index 000000000..e28856b3f
--- /dev/null
+++ b/components/media/volume/block_volume/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_volume_tests.cpp"
+ )
diff --git a/components/media/volume/component.cmake b/components/media/volume/component.cmake
new file mode 100644
index 000000000..9ef173722
--- /dev/null
+++ b/components/media/volume/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/volume.c"
+) \ No newline at end of file
diff --git a/components/media/volume/factory/single_flash/component.cmake b/components/media/volume/factory/single_flash/component.cmake
new file mode 100644
index 000000000..fe1c9c6d7
--- /dev/null
+++ b/components/media/volume/factory/single_flash/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/volume_factory.c"
+) \ No newline at end of file
diff --git a/components/media/volume/factory/single_flash/volume_factory.c b/components/media/volume/factory/single_flash/volume_factory.c
new file mode 100644
index 000000000..ab7bfef48
--- /dev/null
+++ b/components/media/volume/factory/single_flash/volume_factory.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "media/volume/factory/volume_factory.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "media/disk/guid.h"
+#include "media/volume/block_volume/block_volume.h"
+#include "service/block_storage/block_store/block_store.h"
+#include "service/block_storage/factory/block_store_factory.h"
+#include "trace.h"
+
+/**
+ * A volume factory for single flash deployments where underlying block-level
+ * access is provided by a block_store object. The block_store used is provided
+ * by the block_store_factory selected for the deployment. This could construct
+ * any suitable block_store.
+ */
+static struct block_store *single_block_store;
+
+int volume_factory_init(struct uuid_octets *device_uuids, size_t device_uuids_size,
+ size_t *num_device_uuids)
+{
+ assert(device_uuids || !device_uuids_size);
+ assert(num_device_uuids);
+
+ *num_device_uuids = 0;
+ single_block_store = block_store_factory_create();
+
+ if (!single_block_store) {
+ EMSG("Failed to construct block_store");
+ return -EIO;
+ }
+
+ if (device_uuids_size > 0) {
+ struct storage_partition_info device_info;
+ struct uuid_octets uuid;
+
+ /* Query for GPT partition to get info about the parent device */
+ uuid_guid_octets_from_canonical(&uuid, DISK_GUID_UNIQUE_PARTITION_DISK_HEADER);
+
+ psa_status_t psa_status =
+ block_store_get_partition_info(single_block_store, &uuid, &device_info);
+
+ if (psa_status == PSA_SUCCESS)
+ device_uuids[0] = device_info.parent_guid;
+ else
+ memset(&device_uuids[0], 0, sizeof(struct uuid_octets));
+
+ *num_device_uuids = 1;
+ }
+
+ return 0;
+}
+
+void volume_factory_deinit(void)
+{
+ block_store_factory_destroy(single_block_store);
+ single_block_store = NULL;
+}
+
+struct volume *volume_factory_create_volume(const struct uuid_octets *partition_uuid,
+ const struct uuid_octets *device_uuid)
+{
+ struct volume *product = NULL;
+
+ assert(single_block_store);
+
+ /* This factory assumes that all volumes are backed by a single block device */
+ (void)device_uuid;
+
+ struct block_volume *block_volume =
+ (struct block_volume *)malloc(sizeof(struct block_volume));
+
+ if (block_volume) {
+ int status = block_volume_init(block_volume, single_block_store, partition_uuid,
+ &product);
+
+ if (status) {
+ EMSG("Failed to init block volume: %d", status);
+ product = NULL;
+ free(block_volume);
+ }
+ } else {
+ EMSG("Failed to alloc block volume");
+ }
+
+ return product;
+}
+
+void volume_factory_destroy_volume(struct volume *volume)
+{
+ if (volume && volume->io_spec)
+ free((void *)volume->io_spec);
+}
diff --git a/components/media/volume/factory/volume_factory.h b/components/media/volume/factory/volume_factory.h
new file mode 100644
index 000000000..04d70ab9c
--- /dev/null
+++ b/components/media/volume/factory/volume_factory.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_VOLUME_FACTORY_H
+#define MEDIA_VOLUME_FACTORY_H
+
+#include <stddef.h>
+
+#include "common/uuid/uuid.h"
+#include "media/volume/volume.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Initialise the singleton volume_factory
+ *
+ * Initialises the deployment specific volume factory. Once initialised, the volume_factory
+ * will be ready to construct volume objects that can provide IO access to the requested
+ * storage. The details of how the storage is accessed is hidden from the client. A set
+ * of device UUIDs is returned, each identifying a storage device that can potentially be
+ * accessed using a constructed volume.
+ *
+ * \param[out] device_uuids Array of available device UUIDs
+ * \param[in] device_uuids_size Number of slots in the provided array
+ * \param[out] num_device_uuids The number of device UUIDs actually returned
+ *
+ * \return Status (0 on success)
+ */
+int volume_factory_init(struct uuid_octets *device_uuids, size_t device_uuids_size,
+ size_t *num_device_uuids);
+
+/**
+ * \brief De-initialises the volume_factory
+ */
+void volume_factory_deinit(void);
+
+/**
+ * \brief Common interface for constructing volume objects
+ *
+ * The volume_factory provides a common interface for constructing volume objects,
+ * decoupling client code from the details of initialising a concrete volume.
+ * Volume objects created by the factory should also be destroyed by the factory.
+ *
+ * \param[in] partition_uuid Identifies the unit of storage (e.g. a unique partition uuid)
+ * \param[in] device_uuid Identifies the parent device
+ *
+ * \return Pointer to volume or NULL
+ */
+struct volume *volume_factory_create_volume(const struct uuid_octets *partition_uuid,
+ const struct uuid_octets *device_uuid);
+
+/**
+ * \brief Destroys a volume object
+ *
+ * \param[in] volume Volume to destroy
+ */
+void volume_factory_destroy_volume(struct volume *volume);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_VOLUME_FACTORY_H */
diff --git a/components/media/volume/index/component.cmake b/components/media/volume/index/component.cmake
new file mode 100644
index 000000000..2dfcedc3c
--- /dev/null
+++ b/components/media/volume/index/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/volume_index.c"
+) \ No newline at end of file
diff --git a/components/media/volume/index/volume_index.c b/components/media/volume/index/volume_index.c
new file mode 100644
index 000000000..0c6aa999e
--- /dev/null
+++ b/components/media/volume/index/volume_index.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include "volume_index.h"
+
+#ifndef VOLUME_INDEX_MAX_ENTRIES
+#define VOLUME_INDEX_MAX_ENTRIES (8)
+#endif
+
+/**
+ * Singleton index of volume IDs to IO devices.
+ */
+static struct {
+
+ size_t size;
+ struct {
+ unsigned int volume_id;
+ struct volume *volume;
+ } entries[VOLUME_INDEX_MAX_ENTRIES];
+
+} volume_index;
+
+/**
+ * @brief Gets a device for volume IO operations
+ *
+ * @param[in] volume_id Identifies the image
+ * @param[out] dev_handle Handle for IO operations
+ * @param[out] io_spec Opaque configuration data
+ *
+ * This function realizes the interface expected by tf-a components to
+ * provide a concrete IO device for the specified volume ID. When used in
+ * TS deployments, the set of IO devices required for a deployment
+ * are registered during service configuration.
+ */
+int plat_get_image_source(
+ unsigned int volume_id,
+ uintptr_t *dev_handle,
+ uintptr_t *io_spec)
+{
+ struct volume *volume = NULL;
+ int result = volume_index_find(volume_id, &volume);
+
+ if (result == 0) {
+
+ if (volume) {
+
+ *dev_handle = volume->dev_handle;
+ *io_spec = volume->io_spec;
+ } else
+ result = -1;
+ }
+
+ return result;
+}
+
+void volume_index_init(void)
+{
+ volume_index_clear();
+}
+
+void volume_index_clear(void)
+{
+ memset(&volume_index, 0, sizeof(volume_index));
+}
+
+int volume_index_add(
+ unsigned int volume_id,
+ struct volume *volume)
+{
+ int result = -1;
+
+ if (volume_index.size < VOLUME_INDEX_MAX_ENTRIES) {
+ size_t i = volume_index.size;
+
+ ++volume_index.size;
+ volume_index.entries[i].volume_id = volume_id;
+ volume_index.entries[i].volume = volume;
+
+ result = 0;
+ }
+
+ return result;
+}
+
+int volume_index_find(
+ unsigned int volume_id,
+ struct volume **volume)
+{
+ int result = -1;
+
+ for (size_t i = 0; i < volume_index.size; i++) {
+
+ if (volume_index.entries[i].volume_id == volume_id) {
+
+ *volume = volume_index.entries[i].volume;
+ result = 0;
+ break;
+ }
+ }
+
+ return result;
+}
+
+struct volume *volume_index_get(unsigned int index)
+{
+ struct volume *volume = NULL;
+
+ if (index < volume_index.size)
+ volume = volume_index.entries[index].volume;
+
+ return volume;
+}
diff --git a/components/media/volume/index/volume_index.h b/components/media/volume/index/volume_index.h
new file mode 100644
index 000000000..612d0e958
--- /dev/null
+++ b/components/media/volume/index/volume_index.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_VOLUME_INDEX_H
+#define MEDIA_VOLUME_INDEX_H
+
+#include <stdint.h>
+#include <media/volume/volume.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * For tf-a declaration of plat_get_image_source(). Included within C++ extern C
+ * guard to allow for calling from C++.
+ */
+#include <plat/common/platform.h>
+
+/**
+ * @brief Some common volume identifiers
+ *
+ * Volume IDs only need to be unique within a deployment. For convenience,
+ * here are some common volume IDs that may be useful.
+ */
+#define VOLUME_ID_COMMON_BASE (0x10000000)
+#define VOLUME_ID_SECURE_FLASH (VOLUME_ID_COMMON_BASE + 0)
+
+/**
+ * @brief Initialize the volume index
+ *
+ * The volume_index is a singleton that holds the mapping of volume IDs
+ * to concrete volume objects that associate a storage volume with an
+ * IO device that may be used to access storage. The mappings are setup
+ * during deployment configuration to meet the IO needs of the deployment.
+ * The volume_index realizes the tf-a function plat_get_image_source() to
+ * make the mappings available to tf-a components.
+ */
+void volume_index_init(void);
+
+/**
+ * @brief Clears the volume index
+ *
+ * Clears all mappings.
+ */
+void volume_index_clear(void);
+
+/**
+ * @brief Add an entry to the volume index
+ *
+ * @param[in] volume_id Volume identifier
+ * @param[in] volume The volume that extends the base io_dev
+ *
+ * @return 0 if successful
+ */
+int volume_index_add(
+ unsigned int volume_id,
+ struct volume *volume);
+
+/**
+ * @brief Find an added volume by volume index
+ *
+ * @param[in] volume_id Volume identifier
+ * @param[out] volume The volume that extends the base io_dev
+ *
+ * @return 0 if found
+ */
+int volume_index_find(
+ unsigned int volume_id,
+ struct volume **volume);
+
+/**
+ * @brief Iterator function
+ *
+ * @param[in] index 0..n
+ *
+ * @return Pointer to a concrete volume or NULL if iterated beyond final entry
+ */
+struct volume *volume_index_get(unsigned int index);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_VOLUME_INDEX_H */
diff --git a/components/media/volume/volume.c b/components/media/volume/volume.c
new file mode 100644
index 000000000..aa17c2616
--- /dev/null
+++ b/components/media/volume/volume.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "volume.h"
+
+#include <errno.h>
+#include <stddef.h>
+
+void volume_init(struct volume *this_volume, const io_dev_funcs_t *io_dev_funcs,
+ uintptr_t concrete_volume)
+{
+ this_volume->dev_info.funcs = io_dev_funcs;
+ this_volume->dev_info.info = concrete_volume;
+
+ this_volume->dev_handle = (uintptr_t)&this_volume->dev_info;
+ this_volume->io_spec = concrete_volume;
+
+ this_volume->io_handle = 0;
+
+ /* Optional functions that a concrete volume may provide */
+ this_volume->erase = NULL;
+ this_volume->get_storage_ids = NULL;
+}
+
+int volume_open(struct volume *this_volume)
+{
+ return io_open(this_volume->dev_handle, this_volume->io_spec, &this_volume->io_handle);
+}
+
+int volume_close(struct volume *this_volume)
+{
+ return io_close(this_volume->io_handle);
+}
+
+int volume_seek(struct volume *this_volume, io_seek_mode_t mode, signed long long offset)
+{
+ return io_seek(this_volume->io_handle, mode, offset);
+}
+
+int volume_size(struct volume *this_volume, size_t *size)
+{
+ return io_size(this_volume->io_handle, size);
+}
+
+int volume_read(struct volume *this_volume, uintptr_t buffer, size_t length, size_t *length_read)
+{
+ return io_read(this_volume->io_handle, buffer, length, length_read);
+}
+
+int volume_write(struct volume *this_volume, const uintptr_t buffer, size_t length,
+ size_t *length_written)
+{
+ return io_write(this_volume->io_handle, buffer, length, length_written);
+}
+
+int volume_erase(struct volume *this_volume)
+{
+ return (this_volume->erase) ? this_volume->erase(this_volume->dev_info.info) : 0;
+}
+
+int volume_get_storage_ids(struct volume *this_volume, struct uuid_octets *partition_guid,
+ struct uuid_octets *parent_guid)
+{
+ if (this_volume->get_storage_ids)
+ return this_volume->get_storage_ids(this_volume->dev_info.info, partition_guid,
+ parent_guid);
+
+ return -EIO;
+}
diff --git a/components/media/volume/volume.h b/components/media/volume/volume.h
new file mode 100644
index 000000000..1e335eb09
--- /dev/null
+++ b/components/media/volume/volume.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_VOLUME_H
+#define MEDIA_VOLUME_H
+
+#include <stddef.h>
+
+#include "common/uuid/uuid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Export tf-a version with C++ linkage support.
+ */
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+
+/**
+ * A volume can be used to access storage as a single seekable volume
+ * that may be accessed using file io type operations. The base volume
+ * extends the TF-A io_dev to add an erase operation to enable the entire
+ * volume to be erased prior to performing write operations. This is useful
+ * when doing things like installing firmware into a raw disk partition.
+ * Alternative concrete volume implementations are possible to suite different
+ * classes of storage. If a concrete volume does not support erase, the
+ * erase function pointer may be set to NULL;
+ */
+struct volume {
+ /* IO device handle for volume access */
+ uintptr_t dev_handle;
+
+ /* Opaque IO spec */
+ uintptr_t io_spec;
+
+ /* Base IO device */
+ io_dev_info_t dev_info;
+
+ /* Handle for IO operations */
+ uintptr_t io_handle;
+
+ /* Optional function to erase the volume */
+ int (*erase)(uintptr_t context);
+
+ /* Optional function to get storage IDs for the volume */
+ int (*get_storage_ids)(uintptr_t context, struct uuid_octets *partition_guid,
+ struct uuid_octets *parent_guid);
+};
+
+/**
+ * @brief Initialize the base volume structure
+ *
+ * Called by a concrete volume to initialize the base volume and io_dev.
+ *
+ * @param[in] this_volume The subject volume
+ * @param[in] io_dev_funcs io_dev function struct for concrete handlers
+ * @param[in] concrete_volume Pointer to the concrete volume instance
+ */
+void volume_init(struct volume *this_volume, const io_dev_funcs_t *io_dev_funcs,
+ uintptr_t concrete_volume);
+
+/**
+ * @brief Open the volume for IO operations
+ *
+ * @param[in] this_volume The subject volume
+ *
+ * @return 0 on success
+ */
+int volume_open(struct volume *this_volume);
+
+/**
+ * @brief Close the volume when done with IO operations
+ *
+ * @param[in] this_volume The subject volume
+ *
+ * @return 0 on success
+ */
+int volume_close(struct volume *this_volume);
+
+/**
+ * @brief Seek to the specified position
+ *
+ * @param[in] this_volume The subject volume
+ * @param[in] mode See io_storage.h for options
+ * @param[in] offset Seek offset
+ *
+ * @return 0 on success
+ */
+int volume_seek(struct volume *this_volume, io_seek_mode_t mode, signed long long offset);
+
+/**
+ * @brief Get the size of the volume
+ *
+ * @param[in] this_volume The subject volume
+ * @param[out] size Size in bytes of the volume
+ *
+ * @return 0 on success
+ */
+int volume_size(struct volume *this_volume, size_t *size);
+
+/**
+ * @brief Read from the volume
+ *
+ * Reads from the current seek position.
+ *
+ * @param[in] this_volume The subject volume
+ * @param[in] buffer Buffer to put read data
+ * @param[in] length Requested read length
+ * @param[out] length_read Actual length read
+ *
+ * @return 0 on success
+ */
+int volume_read(struct volume *this_volume, uintptr_t buffer, size_t length, size_t *length_read);
+
+/**
+ * @brief Write the volume
+ *
+ * Write from the current seek position.
+ *
+ * @param[in] this_volume The subject volume
+ * @param[in] buffer Buffer containing data to write
+ * @param[in] length Requested write length
+ * @param[out] length_read Actual write read
+ *
+ * @return 0 on success
+ */
+int volume_write(struct volume *this_volume, const uintptr_t buffer, size_t length,
+ size_t *length_written);
+
+/**
+ * @brief Erase the entire volume
+ *
+ * @param[in] this_volume The subject volume
+ *
+ * @return 0 on success
+ */
+int volume_erase(struct volume *this_volume);
+
+/**
+ * @brief Get GUIDs to identify the storage associated with the volume
+ *
+ * If supported by a concrete volume
+ *
+ * @param[in] this_volume The subject volume
+ * @param[out] partition_guid GUID for the logical partition
+ * @param[out] parent_guid GUID for a parent device e.g. a disk GUID
+ *
+ * @return 0 on success, ENOSYS if not supported
+ */
+int volume_get_storage_ids(struct volume *this_volume, struct uuid_octets *partition_guid,
+ struct uuid_octets *parent_guid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_VOLUME_H */
diff --git a/components/messaging/ffa/libsp/component.cmake b/components/messaging/ffa/libsp/component.cmake
index a21c6309c..64e8814b9 100644
--- a/components/messaging/ffa/libsp/component.cmake
+++ b/components/messaging/ffa/libsp/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -21,7 +21,7 @@ target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/sp_rxtx.c"
)
-set_property(TARGET ${TGT} PROPERTY PUBLIC_HEADER
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
${CMAKE_CURRENT_LIST_DIR}/include/ffa_api.h
${CMAKE_CURRENT_LIST_DIR}/include/ffa_api_defines.h
${CMAKE_CURRENT_LIST_DIR}/include/ffa_api_types.h
@@ -49,5 +49,5 @@ endif()
target_include_directories(${TGT}
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
- "$<INSTALL_INTERFACE:include>"
+ "$<INSTALL_INTERFACE:${TS_ENV}/include>"
)
diff --git a/components/messaging/ffa/libsp/ffa.c b/components/messaging/ffa/libsp/ffa.c
index 648d3c823..6a5137927 100644
--- a/components/messaging/ffa/libsp/ffa.c
+++ b/components/messaging/ffa/libsp/ffa.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*/
#include <assert.h> // for assert
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint16_t, uintptr_t, U
+#include <string.h> // for memcpy
#include "ffa_api.h" // for FFA_OK, ffa_interrupt_handler, ffa_fea...
#include "ffa_api_defines.h" // for FFA_PARAM_MBZ, FFA_OK, FFA_ERROR, FFA_...
#include "ffa_api_types.h" // for ffa_result, ffa_direct_msg, ffa_uuid
@@ -33,11 +34,20 @@ static inline void ffa_unpack_direct_msg(struct ffa_params *svc_result,
msg->function_id = svc_result->a0;
msg->source_id = (svc_result->a1 >> 16);
msg->destination_id = svc_result->a1;
- msg->args[0] = svc_result->a3;
- msg->args[1] = svc_result->a4;
- msg->args[2] = svc_result->a5;
- msg->args[3] = svc_result->a6;
- msg->args[4] = svc_result->a7;
+
+ if (FFA_IS_32_BIT_FUNC(msg->function_id)) {
+ msg->args.args32[0] = svc_result->a3;
+ msg->args.args32[1] = svc_result->a4;
+ msg->args.args32[2] = svc_result->a5;
+ msg->args.args32[3] = svc_result->a6;
+ msg->args.args32[4] = svc_result->a7;
+ } else {
+ msg->args.args64[0] = svc_result->a3;
+ msg->args.args64[1] = svc_result->a4;
+ msg->args.args64[2] = svc_result->a5;
+ msg->args.args64[3] = svc_result->a6;
+ msg->args.args64[4] = svc_result->a7;
+ }
}
/*
@@ -133,13 +143,17 @@ ffa_result ffa_rxtx_map(const void *tx_buffer, const void *rx_buffer,
page_count = SHIFT_U32(page_count & FFA_RXTX_MAP_PAGE_COUNT_MASK,
FFA_RXTX_MAP_PAGE_COUNT_SHIFT);
- ffa_svc(FFA_RXTX_MAP_32, (uintptr_t)tx_buffer, (uintptr_t)rx_buffer,
+ ffa_svc(FFA_RXTX_MAP_64, (uintptr_t)tx_buffer, (uintptr_t)rx_buffer,
page_count, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
FFA_PARAM_MBZ, &result);
if (result.a0 == FFA_ERROR)
return ffa_get_errorcode(&result);
+ /*
+ * There are no 64-bit parameters returned with FFA_SUCCESS, the SPMC
+ * will use the default 32-bit version.
+ */
assert(result.a0 == FFA_SUCCESS_32);
return FFA_OK;
}
@@ -213,7 +227,7 @@ ffa_result ffa_msg_wait(struct ffa_direct_msg *msg)
if (result.a0 == FFA_ERROR) {
return ffa_get_errorcode(&result);
- } else if (result.a0 == FFA_MSG_SEND_DIRECT_REQ_32) {
+ } else if (FFA_TO_32_BIT_FUNC(result.a0) == FFA_MSG_SEND_DIRECT_REQ_32) {
ffa_unpack_direct_msg(&result, msg);
} else {
assert(result.a0 == FFA_SUCCESS_32);
@@ -223,13 +237,15 @@ ffa_result ffa_msg_wait(struct ffa_direct_msg *msg)
return FFA_OK;
}
-ffa_result ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
- uint32_t a1, uint32_t a2, uint32_t a3,
- uint32_t a4, struct ffa_direct_msg *msg)
+static ffa_result ffa_msg_send_direct_req(uint32_t function_id, uint32_t resp_id,
+ uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ struct ffa_direct_msg *msg)
{
struct ffa_params result = {0};
- ffa_svc(FFA_MSG_SEND_DIRECT_REQ_32,
+ ffa_svc(function_id,
SHIFT_U32(source, FFA_MSG_SEND_DIRECT_REQ_SOURCE_ID_SHIFT) |
dest, FFA_PARAM_MBZ, a0, a1, a2, a3, a4, &result);
@@ -240,7 +256,7 @@ ffa_result ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
if (result.a0 == FFA_ERROR) {
return ffa_get_errorcode(&result);
- } else if (result.a0 == FFA_MSG_SEND_DIRECT_RESP_32) {
+ } else if (result.a0 == resp_id) {
ffa_unpack_direct_msg(&result, msg);
} else {
assert(result.a0 == FFA_SUCCESS_32);
@@ -250,13 +266,36 @@ ffa_result ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
return FFA_OK;
}
-ffa_result ffa_msg_send_direct_resp(uint16_t source, uint16_t dest, uint32_t a0,
- uint32_t a1, uint32_t a2, uint32_t a3,
- uint32_t a4, struct ffa_direct_msg *msg)
+ffa_result ffa_msg_send_direct_req_32(uint16_t source, uint16_t dest,
+ uint32_t a0, uint32_t a1, uint32_t a2,
+ uint32_t a3, uint32_t a4,
+ struct ffa_direct_msg *msg)
+{
+ return ffa_msg_send_direct_req(FFA_MSG_SEND_DIRECT_REQ_32,
+ FFA_MSG_SEND_DIRECT_RESP_32,
+ source, dest, a0, a1, a2, a3, a4, msg);
+}
+
+ffa_result ffa_msg_send_direct_req_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ struct ffa_direct_msg *msg)
+{
+ return ffa_msg_send_direct_req(FFA_MSG_SEND_DIRECT_REQ_64,
+ FFA_MSG_SEND_DIRECT_RESP_64,
+ source, dest, a0, a1, a2, a3, a4, msg);
+}
+
+static ffa_result ffa_msg_send_direct_resp(uint32_t function_id,
+ uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1,
+ uint64_t a2, uint64_t a3,
+ uint64_t a4,
+ struct ffa_direct_msg *msg)
{
struct ffa_params result = {0};
- ffa_svc(FFA_MSG_SEND_DIRECT_RESP_32,
+ ffa_svc(function_id,
SHIFT_U32(source, FFA_MSG_SEND_DIRECT_RESP_SOURCE_ID_SHIFT) |
dest, FFA_PARAM_MBZ, a0, a1, a2, a3, a4, &result);
@@ -267,7 +306,7 @@ ffa_result ffa_msg_send_direct_resp(uint16_t source, uint16_t dest, uint32_t a0,
if (result.a0 == FFA_ERROR) {
return ffa_get_errorcode(&result);
- } else if (result.a0 == FFA_MSG_SEND_DIRECT_REQ_32) {
+ } else if (FFA_TO_32_BIT_FUNC(result.a0) == FFA_MSG_SEND_DIRECT_REQ_32) {
ffa_unpack_direct_msg(&result, msg);
} else {
assert(result.a0 == FFA_SUCCESS_32);
@@ -277,21 +316,44 @@ ffa_result ffa_msg_send_direct_resp(uint16_t source, uint16_t dest, uint32_t a0,
return FFA_OK;
}
+ffa_result ffa_msg_send_direct_resp_32(uint16_t source, uint16_t dest,
+ uint32_t a0, uint32_t a1, uint32_t a2,
+ uint32_t a3, uint32_t a4,
+ struct ffa_direct_msg *msg)
+{
+ return ffa_msg_send_direct_resp(FFA_MSG_SEND_DIRECT_RESP_32, source,
+ dest, a0, a1, a2, a3, a4, msg);
+}
+
+ffa_result ffa_msg_send_direct_resp_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ struct ffa_direct_msg *msg)
+{
+ return ffa_msg_send_direct_resp(FFA_MSG_SEND_DIRECT_RESP_64, source,
+ dest, a0, a1, a2, a3, a4, msg);
+}
+
ffa_result ffa_mem_donate(uint32_t total_length, uint32_t fragment_length,
void *buffer_address, uint32_t page_count,
uint64_t *handle)
{
struct ffa_params result = {0};
- ffa_svc(FFA_MEM_DONATE_32, total_length, fragment_length,
- (uintptr_t)buffer_address, page_count, FFA_PARAM_MBZ,
- FFA_PARAM_MBZ, FFA_PARAM_MBZ, &result);
+ ffa_svc((buffer_address) ? FFA_MEM_DONATE_64 : FFA_MEM_DONATE_32,
+ total_length, fragment_length, (uintptr_t)buffer_address,
+ page_count, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ &result);
if (result.a0 == FFA_ERROR) {
*handle = 0U;
return ffa_get_errorcode(&result);
}
+ /*
+ * There are no 64-bit parameters returned with FFA_SUCCESS, the SPMC
+ * will use the default 32-bit version.
+ */
assert(result.a0 == FFA_SUCCESS_32);
*handle = reg_pair_to_64(result.a3, result.a2);
return FFA_OK;
@@ -309,15 +371,20 @@ ffa_result ffa_mem_lend(uint32_t total_length, uint32_t fragment_length,
{
struct ffa_params result = {0};
- ffa_svc(FFA_MEM_LEND_32, total_length, fragment_length,
- (uintptr_t)buffer_address, page_count, FFA_PARAM_MBZ,
- FFA_PARAM_MBZ, FFA_PARAM_MBZ, &result);
+ ffa_svc((buffer_address) ? FFA_MEM_LEND_64 : FFA_MEM_LEND_32,
+ total_length, fragment_length, (uintptr_t)buffer_address,
+ page_count, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ &result);
if (result.a0 == FFA_ERROR) {
*handle = 0U;
return ffa_get_errorcode(&result);
}
+ /*
+ * There are no 64-bit parameters returned with FFA_SUCCESS, the SPMC
+ * will use the default 32-bit version.
+ */
assert(result.a0 == FFA_SUCCESS_32);
*handle = reg_pair_to_64(result.a3, result.a2);
return FFA_OK;
@@ -335,15 +402,20 @@ ffa_result ffa_mem_share(uint32_t total_length, uint32_t fragment_length,
{
struct ffa_params result = {0};
- ffa_svc(FFA_MEM_SHARE_32, total_length, fragment_length,
- (uintptr_t)buffer_address, page_count, FFA_PARAM_MBZ,
- FFA_PARAM_MBZ, FFA_PARAM_MBZ, &result);
+ ffa_svc((buffer_address) ? FFA_MEM_SHARE_64 : FFA_MEM_SHARE_32,
+ total_length, fragment_length, (uintptr_t)buffer_address,
+ page_count, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ &result);
if (result.a0 == FFA_ERROR) {
*handle = 0U;
return ffa_get_errorcode(&result);
}
+ /*
+ * There are no 64-bit parameters returned with FFA_SUCCESS, the SPMC
+ * will use the default 32-bit version.
+ */
assert(result.a0 == FFA_SUCCESS_32);
*handle = reg_pair_to_64(result.a3, result.a2);
return FFA_OK;
@@ -362,9 +434,10 @@ ffa_result ffa_mem_retrieve_req(uint32_t total_length, uint32_t fragment_length,
{
struct ffa_params result = {0};
- ffa_svc(FFA_MEM_RETRIEVE_REQ_32, total_length, fragment_length,
- (uintptr_t)buffer_address, page_count, FFA_PARAM_MBZ,
- FFA_PARAM_MBZ, FFA_PARAM_MBZ, &result);
+ ffa_svc((buffer_address) ? FFA_MEM_RETRIEVE_REQ_64 : FFA_MEM_RETRIEVE_REQ_32,
+ total_length, fragment_length, (uintptr_t)buffer_address,
+ page_count, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ &result);
if (result.a0 == FFA_ERROR) {
*resp_total_length = 0U;
@@ -419,3 +492,77 @@ ffa_result ffa_mem_reclaim(uint64_t handle, uint32_t flags)
assert(result.a0 == FFA_SUCCESS_32);
return FFA_OK;
}
+
+ffa_result ffa_mem_perm_get(const void *base_address, uint32_t *mem_perm)
+{
+ struct ffa_params result = {0};
+
+ ffa_svc(FFA_MEM_PERM_GET, (uintptr_t)base_address, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, &result);
+
+ if (result.a0 == FFA_ERROR)
+ return ffa_get_errorcode(&result);
+
+ assert(result.a0 == FFA_SUCCESS_32);
+ *mem_perm = result.a2;
+ return FFA_OK;
+}
+
+ffa_result ffa_mem_perm_set(const void *base_address, uint32_t page_count,
+ uint32_t mem_perm)
+{
+ struct ffa_params result = {0};
+
+ assert((mem_perm & FFA_MEM_PERM_RESERVED_MASK) == 0);
+
+ ffa_svc(FFA_MEM_PERM_SET, (uintptr_t)base_address, page_count, mem_perm,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ &result);
+
+ if (result.a0 == FFA_ERROR)
+ return ffa_get_errorcode(&result);
+
+ assert(result.a0 == FFA_SUCCESS_32);
+ return FFA_OK;
+}
+
+ffa_result ffa_console_log_32(const char *message, size_t length)
+{
+ struct ffa_params result = {0};
+ uint32_t char_lists[6] = {0};
+
+ assert(length > 0 && length <= sizeof(char_lists));
+
+ memcpy(char_lists, message, MIN(length, sizeof(char_lists)));
+
+ ffa_svc(FFA_CONSOLE_LOG_32, length, char_lists[0], char_lists[1],
+ char_lists[2], char_lists[3], char_lists[4], char_lists[5],
+ &result);
+
+ if (result.a0 == FFA_ERROR)
+ return ffa_get_errorcode(&result);
+
+ assert(result.a0 == FFA_SUCCESS_32);
+ return FFA_OK;
+}
+
+ffa_result ffa_console_log_64(const char *message, size_t length)
+{
+ struct ffa_params result = {0};
+ uint64_t char_lists[6] = {0};
+
+ assert(length > 0 && length <= sizeof(char_lists));
+
+ memcpy(char_lists, message, MIN(length, sizeof(char_lists)));
+
+ ffa_svc(FFA_CONSOLE_LOG_64, length, char_lists[0], char_lists[1],
+ char_lists[2], char_lists[3], char_lists[4], char_lists[5],
+ &result);
+
+ if (result.a0 == FFA_ERROR)
+ return ffa_get_errorcode(&result);
+
+ assert(result.a0 == FFA_SUCCESS_32);
+ return FFA_OK;
+}
diff --git a/components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c b/components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c
index 681357304..f62d3f2bd 100644
--- a/components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c
+++ b/components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*/
#include "ffa_direct_msg_routing_extension.h"
@@ -8,8 +8,9 @@
#include <stdbool.h>
#define SP_ID_INVALID FFA_ID_GET_ID_MASK
-#define FFA_ROUTING_EXT_RC_BIT BIT(0)
-#define FFA_ROUTING_EXT_ERROR_BIT BIT(1)
+#define FFA_ROUTING_EXT_RC_BIT BIT32(31)
+#define FFA_ROUTING_EXT_ERROR_BIT BIT32(30)
+#define FFA_ROUTING_EXT_BITS_MASK (FFA_ROUTING_EXT_RC_BIT | FFA_ROUTING_EXT_ERROR_BIT)
enum sp_rc_state { idle = 0, root, leaf, rc_root, internal, forwarding };
@@ -20,23 +21,23 @@ static uint16_t callee_id = SP_ID_INVALID;
static bool is_rc_message(const struct ffa_direct_msg *msg)
{
- return msg->args[0] & FFA_ROUTING_EXT_RC_BIT;
+ return msg->args.args32[0] & FFA_ROUTING_EXT_RC_BIT;
}
static bool is_error_message(const struct ffa_direct_msg *msg)
{
- return msg->args[0] & FFA_ROUTING_EXT_ERROR_BIT;
+ return msg->args.args32[0] & FFA_ROUTING_EXT_ERROR_BIT;
}
static ffa_result get_error_code_from_message(const struct ffa_direct_msg *msg)
{
- return (ffa_result)msg->args[1];
+ return (ffa_result)msg->args.args32[1];
}
static ffa_result send_rc_error_message(struct ffa_direct_msg *req,
ffa_result error_code)
{
- return ffa_msg_send_direct_resp(req->destination_id, req->source_id,
+ return ffa_msg_send_direct_resp_32(req->destination_id, req->source_id,
(FFA_ROUTING_EXT_ERROR_BIT |
FFA_ROUTING_EXT_RC_BIT),
error_code, 0, 0, 0, req);
@@ -45,7 +46,7 @@ static ffa_result send_rc_error_message(struct ffa_direct_msg *req,
static ffa_result send_rc_error_message_to_rc_root(struct ffa_direct_msg *resp,
ffa_result error_code)
{
- return ffa_msg_send_direct_req(own_id, callee_id,
+ return ffa_msg_send_direct_req_32(own_id, callee_id,
(FFA_ROUTING_EXT_RC_BIT |
FFA_ROUTING_EXT_ERROR_BIT),
error_code, 0, 0, 0, resp);
@@ -99,6 +100,9 @@ static ffa_result request_received_hook(struct ffa_direct_msg *req)
caller_id = req->source_id;
callee_id = SP_ID_INVALID;
+ if (FFA_IS_32_BIT_FUNC(req->function_id))
+ req->args.args32[0] &= ~FFA_ROUTING_EXT_BITS_MASK;
+
return FFA_OK;
}
@@ -107,10 +111,17 @@ ffa_result ffa_direct_msg_routing_ext_wait_post_hook(struct ffa_direct_msg *req)
return request_received_hook(req);
}
-void ffa_direct_msg_routing_ext_req_pre_hook(struct ffa_direct_msg *req)
+ffa_result ffa_direct_msg_routing_ext_req_pre_hook(struct ffa_direct_msg *req)
{
+ if (FFA_IS_32_BIT_FUNC(req->function_id)) {
+ if (req->args.args32[0] & FFA_ROUTING_EXT_BITS_MASK)
+ return FFA_INVALID_PARAMETERS;
+ }
+
state = internal;
callee_id = req->destination_id;
+
+ return FFA_OK;
}
ffa_result ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg *resp)
@@ -128,10 +139,10 @@ ffa_result ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg *resp)
/* Forwarding RC request towards the root (normal world) */
state = forwarding;
- ffa_res = ffa_msg_send_direct_resp(own_id, caller_id,
- resp->args[0], resp->args[1],
- resp->args[2], resp->args[3],
- resp->args[4], &rc_resp);
+ ffa_res = ffa_msg_send_direct_resp_32(own_id, caller_id,
+ resp->args.args32[0], resp->args.args32[1],
+ resp->args.args32[2], resp->args.args32[3],
+ resp->args.args32[4], &rc_resp);
if (ffa_res != FFA_OK)
goto forward_ffa_error_to_rc_root;
@@ -145,9 +156,9 @@ ffa_result ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg *resp)
/* Forwarding RC response towards the RC root. */
state = internal;
- ffa_res = ffa_msg_send_direct_req(
- own_id, callee_id, rc_resp.args[0], rc_resp.args[1],
- rc_resp.args[2], rc_resp.args[3], rc_resp.args[4],
+ ffa_res = ffa_msg_send_direct_req_32(
+ own_id, callee_id, rc_resp.args.args32[0], rc_resp.args.args32[1],
+ rc_resp.args.args32[2], rc_resp.args.args32[3], rc_resp.args.args32[4],
resp);
goto break_on_ffa_error;
@@ -179,11 +190,18 @@ void ffa_direct_msg_routing_ext_req_error_hook(void)
callee_id = SP_ID_INVALID;
}
-void ffa_direct_msg_routing_ext_resp_pre_hook(struct ffa_direct_msg *resp)
+ffa_result ffa_direct_msg_routing_ext_resp_pre_hook(struct ffa_direct_msg *resp)
{
+ if (FFA_IS_32_BIT_FUNC(resp->function_id)) {
+ if (resp->args.args32[0] & FFA_ROUTING_EXT_BITS_MASK)
+ return FFA_INVALID_PARAMETERS;
+ }
+
state = idle;
caller_id = SP_ID_INVALID;
callee_id = SP_ID_INVALID;
+
+ return FFA_OK;
}
ffa_result ffa_direct_msg_routing_ext_resp_post_hook(struct ffa_direct_msg *req)
@@ -195,10 +213,17 @@ void ffa_direct_msg_routing_ext_resp_error_hook(void)
{
}
-void ffa_direct_msg_routing_ext_rc_req_pre_hook(struct ffa_direct_msg *req)
+ffa_result ffa_direct_msg_routing_ext_rc_req_pre_hook(struct ffa_direct_msg *req)
{
- req->args[0] = FFA_ROUTING_EXT_RC_BIT;
+ if (FFA_IS_32_BIT_FUNC(req->function_id)) {
+ if (req->args.args32[0] & FFA_ROUTING_EXT_BITS_MASK)
+ return FFA_INVALID_PARAMETERS;
+ }
+
+ req->args.args32[0] |= FFA_ROUTING_EXT_RC_BIT;
state = rc_root;
+
+ return FFA_OK;
}
ffa_result
diff --git a/components/messaging/ffa/libsp/include/ffa_api.h b/components/messaging/ffa/libsp/include/ffa_api.h
index 63592637b..e18e38153 100644
--- a/components/messaging/ffa/libsp/include/ffa_api.h
+++ b/components/messaging/ffa/libsp/include/ffa_api.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifndef LIBSP_INCLUDE_FFA_API_H_
@@ -126,8 +126,8 @@ ffa_result ffa_msg_wait(struct ffa_direct_msg *msg);
/** Messaging interfaces */
/**
- * @brief Sends a partition message in parameter registers as a request and
- * blocks until the response is available.
+ * @brief Sends a 32 bit partition message in parameter registers as a
+ * request and blocks until the response is available.
* @note The ffa_interrupt_handler function can be called during the
* execution of this function
*
@@ -138,13 +138,14 @@ ffa_result ffa_msg_wait(struct ffa_direct_msg *msg);
*
* @return The FF-A error status code
*/
-ffa_result ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
- uint32_t a1, uint32_t a2, uint32_t a3,
- uint32_t a4, struct ffa_direct_msg *msg);
+ffa_result ffa_msg_send_direct_req_32(uint16_t source, uint16_t dest,
+ uint32_t a0, uint32_t a1, uint32_t a2,
+ uint32_t a3, uint32_t a4,
+ struct ffa_direct_msg *msg);
/**
- * @brief Sends a partition message in parameter registers as a response
- * and blocks until the response is available.
+ * @brief Sends a 64 bit partition message in parameter registers as a
+ * request and blocks until the response is available.
* @note The ffa_interrupt_handler function can be called during the
* execution of this function
*
@@ -155,9 +156,46 @@ ffa_result ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
*
* @return The FF-A error status code
*/
-ffa_result ffa_msg_send_direct_resp(uint16_t source, uint16_t dest, uint32_t a0,
- uint32_t a1, uint32_t a2, uint32_t a3,
- uint32_t a4, struct ffa_direct_msg *msg);
+ffa_result ffa_msg_send_direct_req_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ struct ffa_direct_msg *msg);
+
+/**
+ * @brief Sends a 32 bit partition message in parameter registers as a
+ * response and blocks until the response is available.
+ * @note The ffa_interrupt_handler function can be called during the
+ * execution of this function
+ *
+ * @param[in] source Source endpoint ID
+ * @param[in] dest Destination endpoint ID
+ * @param[in] a0,a1,a2,a3,a4 Implementation defined message values
+ * @param[out] msg The response message
+ *
+ * @return The FF-A error status code
+ */
+ffa_result ffa_msg_send_direct_resp_32(uint16_t source, uint16_t dest,
+ uint32_t a0, uint32_t a1, uint32_t a2,
+ uint32_t a3, uint32_t a4,
+ struct ffa_direct_msg *msg);
+
+/**
+ * @brief Sends a 64 bit partition message in parameter registers as a
+ * response and blocks until the response is available.
+ * @note The ffa_interrupt_handler function can be called during the
+ * execution of this function
+ *
+ * @param[in] source Source endpoint ID
+ * @param[in] dest Destination endpoint ID
+ * @param[in] a0,a1,a2,a3,a4 Implementation defined message values
+ * @param[out] msg The response message
+ *
+ * @return The FF-A error status code
+ */
+ffa_result ffa_msg_send_direct_resp_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ struct ffa_direct_msg *msg);
/**
* Memory management interfaces
@@ -292,6 +330,58 @@ ffa_result ffa_mem_relinquish(void);
ffa_result ffa_mem_reclaim(uint64_t handle, uint32_t flags);
/**
+ * @brief Queries the memory attributes of a memory region. This function
+ * can only access the regions of the SP's own translation regine.
+ * Moreover this interface is only available in the boot phase,
+ * i.e. before invoking FFA_MSG_WAIT interface.
+ *
+ * @param[in] base_address Base VA of a translation granule whose
+ * permission attributes must be returned.
+ * @param[out] mem_perm Permission attributes of the memory region
+ *
+ * @return The FF-A error status code
+ */
+ffa_result ffa_mem_perm_get(const void *base_address, uint32_t *mem_perm);
+
+/**
+ * @brief Sets the memory attributes of a memory regions. This function
+ * can only access the regions of the SP's own translation regine.
+ * Moreover this interface is only available in the boot phase,
+ * i.e. before invoking FFA_MSG_WAIT interface.
+ *
+ * @param[in] base_address Base VA of a memory region whose permission
+ * attributes must be set.
+ * @param[in] page_count Number of translation granule size pages
+ * starting from the Base address whose permissions
+ * must be set.
+ * @param[in] mem_perm Permission attributes to be set for the memory
+ * region
+ * @return The FF-A error status code
+ */
+ffa_result ffa_mem_perm_set(const void *base_address, uint32_t page_count,
+ uint32_t mem_perm);
+
+/**
+ * @brief Allow an entity to provide debug logging to the console. Uses
+ * 32 bit registers to pass characters.
+ *
+ * @param message Message characters
+ * @param length Message length, max FFA_CONSOLE_LOG_32_MAX_LENGTH
+ * @return The FF-A error status code
+ */
+ffa_result ffa_console_log_32(const char *message, size_t length);
+
+/**
+ * @brief Allow an entity to provide debug logging to the console. Uses
+ * 64 bit registers to pass characters.
+ *
+ * @param message Message characters
+ * @param length Message length, max FFA_CONSOLE_LOG_64_MAX_LENGTH
+ * @return The FF-A error status code
+ */
+ffa_result ffa_console_log_64(const char *message, size_t length);
+
+/**
* @brief Interrupt handler prototype. Must be implemented by another
* component.
*
diff --git a/components/messaging/ffa/libsp/include/ffa_api_defines.h b/components/messaging/ffa/libsp/include/ffa_api_defines.h
index 4f2c45761..e5aea4140 100644
--- a/components/messaging/ffa/libsp/include/ffa_api_defines.h
+++ b/components/messaging/ffa/libsp/include/ffa_api_defines.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifndef LIBSP_INCLUDE_FFA_API_DEFINES_H_
@@ -55,10 +55,51 @@
#define FFA_MEM_RECLAIM UINT32_C(0x84000077)
#define FFA_MEM_FRAG_RX UINT32_C(0x8400007A)
#define FFA_MEM_FRAG_TX UINT32_C(0x8400007B)
+#define FFA_MEM_PERM_GET UINT32_C(0x84000088)
+#define FFA_MEM_PERM_SET UINT32_C(0x84000089)
+#define FFA_CONSOLE_LOG_32 UINT32_C(0x8400008A)
+#define FFA_CONSOLE_LOG_64 UINT32_C(0xC400008A)
+
+/* Utility macros */
+#define FFA_TO_32_BIT_FUNC(x) ((x) & (~UINT32_C(0x40000000)))
+#define FFA_TO_64_BIT_FUNC(x) ((x) | UINT32_C(0x40000000))
+#define FFA_IS_32_BIT_FUNC(x) (((x) & UINT32_C(0x40000000)) == 0)
+#define FFA_IS_64_BIT_FUNC(x) (((x) & UINT32_C(0x40000000)) != 0)
/* Special value for MBZ parameters */
#define FFA_PARAM_MBZ UINT32_C(0x0)
+/* Boot information signature */
+#define FFA_BOOT_INFO_SIGNATURE_V1_0 UINT32_C(0x412D4646) /* FF-A ASCII */
+#define FFA_BOOT_INFO_SIGNATURE_V1_1 UINT32_C(0x0FFA)
+
+/* Boot information type */
+#define FFA_BOOT_INFO_TYPE_SHIFT UINT32_C(7)
+#define FFA_BOOT_INFO_TYPE_MASK UINT32_C(1)
+
+#define FFA_BOOT_INFO_TYPE_STD UINT32_C(0)
+#define FFA_BOOT_INFO_TYPE_IMPDEF UINT32_C(1)
+
+/* Boot information ID */
+#define FFA_BOOT_INFO_ID_SHIFT UINT32_C(0)
+#define FFA_BOOT_INFO_ID_MASK GENMASK_32(6, 0)
+
+#define FFA_BOOT_INFO_ID_STD_FDT UINT32_C(0)
+#define FFA_BOOT_INFO_ID_STD_HOB UINT32_C(1)
+
+/* Boot information flags */
+#define FFA_BOOT_INFO_CONTENT_FMT_SHIFT UINT32_C(2)
+#define FFA_BOOT_INFO_CONTENT_FMT_MASK GENMASK_32(1, 0)
+
+#define FFA_BOOT_INFO_CONTENT_FMT_ADDR UINT32_C(0)
+#define FFA_BOOT_INFO_CONTENT_FMT_VAL UINT32_C(1)
+
+#define FFA_BOOT_INFO_NAME_FMT_SHIFT UINT32_C(0)
+#define FFA_BOOT_INFO_NAME_FMT_MASK GENMASK_32(1, 0)
+
+#define FFA_BOOT_INFO_NAME_FMT_STR UINT32_C(0)
+#define FFA_BOOT_INFO_NAME_FMT_UUID UINT32_C(1)
+
/* FFA_VERSION */
#define FFA_VERSION_MAJOR UINT32_C(1)
#define FFA_VERSION_MAJOR_SHIFT UINT32_C(16)
@@ -205,8 +246,41 @@
/* FFA_MEM_TRANSACTION_FLAGS_ZERO_MEMORY is available too */
/* FFA_MEM_TRANSACTION_FLAGS_TYPE_* is available too */
+/* Handle */
+#define FFA_MEM_HANDLE_INVALID GENMASK_64(63, 0)
+
/* Table 11.25: Descriptor to relinquish a memory region */
#define FFA_RELINQUISH_FLAGS_ZERO_MEMORY_AFTER_RELINQUISH BIT32(0)
#define FFA_RELINQUISH_FLAGS_OPERATION_TIME_SLICING BIT32(1)
+/* Flags for memory permission get/set */
+#ifndef FFA_MEM_PERM_PAGE_SIZE
+#define FFA_MEM_PERM_PAGE_SIZE UINT32_C(4096)
+#endif /* FFA_MEM_PERM_PAGE_SIZE */
+
+#define FFA_MEM_PERM_PAGE_MASK (FFA_MEM_PERM_PAGE_SIZE - 1)
+
+#define FFA_MEM_PERM_PAGE_COUNT_MAX GENMASK_32(31, 0)
+
+#define FFA_MEM_PERM_DATA_ACCESS_PERM_INDEX UINT32_C(2)
+#define FFA_MEM_PERM_DATA_ACCESS_PERM_SHIFT UINT32_C(0)
+#define FFA_MEM_PERM_DATA_ACCESS_PERM_MASK GENMASK_32(1, 0)
+
+#define FFA_MEM_PERM_DATA_ACCESS_PERM_NO_ACCESS UINT32_C(0x00)
+#define FFA_MEM_PERM_DATA_ACCESS_PERM_RW UINT32_C(0x01)
+#define FFA_MEM_PERM_DATA_ACCESS_PERM_RESERVED UINT32_C(0x02)
+#define FFA_MEM_PERM_DATA_ACCESS_PERM_RO UINT32_C(0x03)
+
+#define FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_INDEX UINT32_C(2)
+#define FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_MASK BIT(2)
+
+#define FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_X UINT32_C(0x00)
+#define FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_NX BIT(2)
+
+#define FFA_MEM_PERM_RESERVED_MASK GENMASK_32(31, 3)
+
+/* FFA_CONSOLE_LOG */
+#define FFA_CONSOLE_LOG_32_MAX_LENGTH UINT32_C(24)
+#define FFA_CONSOLE_LOG_64_MAX_LENGTH UINT32_C(48)
+
#endif /* LIBSP_INCLUDE_FFA_API_DEFINES_H_ */
diff --git a/components/messaging/ffa/libsp/include/ffa_api_types.h b/components/messaging/ffa/libsp/include/ffa_api_types.h
index 3686e2ead..7156c023d 100644
--- a/components/messaging/ffa/libsp/include/ffa_api_types.h
+++ b/components/messaging/ffa/libsp/include/ffa_api_types.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifndef LIBSP_INCLUDE_FFA_API_TYPES_H_
@@ -11,25 +11,54 @@
#include <stdint.h>
/**
- * Init info
+ * Boot info
*/
/**
* @brief Boot protocol name-value pairs
*/
-struct ffa_name_value_pair {
+struct ffa_name_value_pair_v1_0 {
uint32_t name[4]; /**< Name of the item */
uintptr_t value; /**< Value of the item */
size_t size; /**< Size of the referenced value */
};
/**
- * @brief Structure for passing boot protocol data
+ * @brief Structure for passing boot protocol data (FF-A v1.0)
*/
-struct ffa_init_info {
+struct ffa_boot_info_v1_0 {
uint32_t magic; /**< FF-A */
uint32_t count; /**< Count of name value size pairs */
- struct ffa_name_value_pair nvp[]; /**< Array of name value size pairs */
+ struct ffa_name_value_pair_v1_0 nvp[]; /**< Array of name value size pairs */
+};
+
+struct ffa_boot_info_desc_v1_1 {
+ uint8_t name[16]; /**< Name of boot information passed to the consumer */
+ uint8_t type; /**< Type of boot information passed to the consumer */
+ uint8_t reserved_mbz; /**< Reserved (MBZ) */;
+ uint16_t flags; /**< Flags to describe properties of boot information in this descriptor */
+ uint32_t size; /**< Size (in bytes) of boot info identified by Name and Type fields */
+ uint64_t contents; /**< Value or address of boot info identified by Name and Type fields. */
+} __packed;
+
+/**
+ * @brief Structure for passing boot protocol data (FF-A v1.1)
+ */
+struct ffa_boot_info_header_v1_1 {
+ uint32_t signature; /**< 0x0ffa */
+ uint32_t version; /**< FF-A version: bit[31]: MBZ, bit[30:16] major version number,
+ bit[15:0] minor version number */
+ uint32_t size; /**< Size of boot information blob spanning contiguous memory */
+ uint32_t desc_size; /**< Size of each boot information descriptor in the array */
+ uint32_t desc_cnt; /**< Count of boot information descriptors in the array */
+ uint32_t desc_offs; /**< Offset to array of boot information descriptors */
+ uint64_t reserved_mbz; /**< Reserved (MBZ) */
+} __packed;
+
+union ffa_boot_info {
+ uint32_t signature;
+ struct ffa_boot_info_v1_0 boot_info_v1_0;
+ struct ffa_boot_info_header_v1_1 boot_info_v1_1;
};
/**
@@ -80,7 +109,10 @@ struct ffa_direct_msg {
uint32_t function_id;
uint16_t source_id;
uint16_t destination_id;
- uint32_t args[5];
+ union {
+ uint32_t args32[5];
+ uint64_t args64[5];
+ } args;
};
/**
diff --git a/components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h b/components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h
index 3715f50f5..894420000 100644
--- a/components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h
+++ b/components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h
@@ -14,22 +14,18 @@
extern "C" {
#endif
-ffa_result
-ffa_direct_msg_routing_ext_wait_post_hook(struct ffa_direct_msg *req);
+ffa_result ffa_direct_msg_routing_ext_wait_post_hook(struct ffa_direct_msg *req);
-void ffa_direct_msg_routing_ext_req_pre_hook(struct ffa_direct_msg *req);
-ffa_result
-ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg *resp);
+ffa_result ffa_direct_msg_routing_ext_req_pre_hook(struct ffa_direct_msg *req);
+ffa_result ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg *resp);
void ffa_direct_msg_routing_ext_req_error_hook(void);
-void ffa_direct_msg_routing_ext_resp_pre_hook(struct ffa_direct_msg *resp);
-ffa_result
-ffa_direct_msg_routing_ext_resp_post_hook(struct ffa_direct_msg *req);
+ffa_result ffa_direct_msg_routing_ext_resp_pre_hook(struct ffa_direct_msg *resp);
+ffa_result ffa_direct_msg_routing_ext_resp_post_hook(struct ffa_direct_msg *req);
void ffa_direct_msg_routing_ext_resp_error_hook(void);
-void ffa_direct_msg_routing_ext_rc_req_pre_hook(struct ffa_direct_msg *req);
-ffa_result
-ffa_direct_msg_routing_ext_rc_req_post_hook(struct ffa_direct_msg *resp);
+ffa_result ffa_direct_msg_routing_ext_rc_req_pre_hook(struct ffa_direct_msg *req);
+ffa_result ffa_direct_msg_routing_ext_rc_req_post_hook(struct ffa_direct_msg *resp);
void ffa_direct_msg_routing_ext_rc_req_error_hook(void);
#ifdef __cplusplus
diff --git a/components/messaging/ffa/libsp/include/sp_api.h b/components/messaging/ffa/libsp/include/sp_api.h
index 3c432bb64..b220c9103 100644
--- a/components/messaging/ffa/libsp/include/sp_api.h
+++ b/components/messaging/ffa/libsp/include/sp_api.h
@@ -30,9 +30,9 @@ void sp_interrupt_handler(uint32_t interrupt_id);
* @brief Entry point of the SP's application code. SPs must implement this
* function.
*
- * @param init_info The boot info
+ * @param boot_info The boot info
*/
-void __noreturn sp_main(struct ffa_init_info *init_info);
+void __noreturn sp_main(union ffa_boot_info *boot_info);
#ifdef __cplusplus
}
diff --git a/components/messaging/ffa/libsp/include/sp_discovery.h b/components/messaging/ffa/libsp/include/sp_discovery.h
index a85e94679..977c87544 100644
--- a/components/messaging/ffa/libsp/include/sp_discovery.h
+++ b/components/messaging/ffa/libsp/include/sp_discovery.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*/
#ifndef LIBSP_INCLUDE_SP_DISCOVERY_H_
@@ -60,13 +60,18 @@ sp_result sp_discovery_partition_id_get(const struct sp_uuid *uuid,
/**
* @brief Queries the information about a partition by its UUID.
*
- * @param[in] uuid The UUID of the partition
- * @param[out] info The partition information
+ * @param[in] uuid The UUID of the partition
+ * @param[out] info The partition information
+ * @param[in,out] count As an input value it specifies the count of partition
+ * info structures that would fit into the output buffer.
+ * As an output it indicates the count of the valid
+ * entries in the buffer.
*
- * @return The SP API result
+ * @return The SP API result
*/
sp_result sp_discovery_partition_info_get(const struct sp_uuid *uuid,
- struct sp_partition_info *info);
+ struct sp_partition_info *info,
+ uint32_t *count);
/**
* @brief Queries partition information of all partitions.
diff --git a/components/messaging/ffa/libsp/include/sp_memory_management.h b/components/messaging/ffa/libsp/include/sp_memory_management.h
index 16a17ec68..ec76a3d8e 100644
--- a/components/messaging/ffa/libsp/include/sp_memory_management.h
+++ b/components/messaging/ffa/libsp/include/sp_memory_management.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifndef LIBSP_INCLUDE_SP_MEMORY_MANAGEMENT_H_
@@ -244,6 +244,36 @@ struct sp_memory_region {
};
/**
+ * @brief Enum for describing data access permissions in
+ * sp_memory_permission_get/set calls (FFA_MEM_PERM_GET/SET).
+ */
+enum sp_mem_perm_data_access_permission {
+ sp_mem_perm_data_perm_no_access = 0x00,
+ sp_mem_perm_data_perm_read_write = 0x01,
+ sp_mem_perm_data_perm_reserved = 0x02,
+ sp_mem_perm_data_perm_read_only = 0x03
+};
+
+/**
+ * @brief Enum for describing instruction access permissions in
+ * sp_memory_permission_get/set calls (FFA_MEM_PERM_GET/SET).
+ */
+enum sp_mem_perm_instruction_access_permission {
+ sp_mem_perm_instruction_perm_executable = 0x00,
+ sp_mem_perm_instruction_perm_non_executable = 0x01
+};
+
+/**
+ * @brief Struct for describing memory access setting in
+ * sp_memory_permission_get/set calls (FFA_MEM_PERM_GET/SET).
+ *
+ */
+struct sp_mem_perm {
+ enum sp_mem_perm_data_access_permission data_access;
+ enum sp_mem_perm_instruction_access_permission instruction_access;
+};
+
+/**
* @brief Starts a transaction to transfer of ownership of a memory region
* from a Sender endpoint to a Receiver endpoint.
*
@@ -351,7 +381,7 @@ sp_result sp_memory_share_dynamic_is_supported(bool *supported);
*
* @param[in] descriptor The memory descriptor
* @param[in,out] acc_desc Access descriptor
- * @param[in,out regions Memory region array
+ * @param[in,out] regions Memory region array
* @param[in] in_region_count Count of the specified regions, can be 0
* @param[in,out] out_region_count Count of the reserved space of in the
* regions buffer for retrieved regions. After
@@ -409,6 +439,37 @@ sp_result sp_memory_relinquish(uint64_t handle, const uint16_t endpoints[],
*/
sp_result sp_memory_reclaim(uint64_t handle, uint32_t flags);
+/**
+ * @brief Queries the memory attributes of a memory region. It can only
+ * access the regions of the SP's own translation regine. Moreover
+ * this function is only available in the boot phase, i.e. before
+ * calling sp_msg_wait.
+ *
+ *
+ * @param[in] base_address Base VA of a translation granule whose
+ * permission attributes must be returned.
+ * @param[out] mem_perm Permission attributes of the memory region
+ * @return The SP API result
+ */
+sp_result sp_memory_permission_get(const void *base_address,
+ struct sp_mem_perm *mem_perm);
+
+/**
+ * @brief Sets the memory attributes of a memory regions. It can only
+ * access the regions of the SP's own translation regine. Moreover
+ * this function is only available in the boot phase, i.e. before
+ * calling sp_msg_wait.
+ *
+ * @param[in] base_address Base VA of a memory region whose permission
+ * attributes must be set.
+ * @param[in] region_size Memory regions size in bytes
+ * @param[in] mem_perm Permission attributes to be set for the memory
+ * region
+ * @return The SP API result
+ */
+sp_result sp_memory_permission_set(const void *base_address, size_t region_size,
+ const struct sp_mem_perm *mem_perm);
+
#ifdef __cplusplus
}
#endif
diff --git a/components/messaging/ffa/libsp/include/sp_messaging.h b/components/messaging/ffa/libsp/include/sp_messaging.h
index 4bb45f767..c1c5a7a0d 100644
--- a/components/messaging/ffa/libsp/include/sp_messaging.h
+++ b/components/messaging/ffa/libsp/include/sp_messaging.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifndef LIBSP_INCLUDE_SP_MESSAGING_H_
@@ -9,13 +9,14 @@
#include "sp_api_defines.h"
#include "sp_api_types.h"
+#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
-#define SP_MSG_ARG_COUNT (4)
+#define SP_MSG_ARG_COUNT (5)
/**
* @brief SP message type
@@ -23,7 +24,11 @@ extern "C" {
struct sp_msg {
uint16_t source_id;
uint16_t destination_id;
- uint32_t args[SP_MSG_ARG_COUNT];
+ bool is_64bit_message;
+ union {
+ uint32_t args32[SP_MSG_ARG_COUNT];
+ uint64_t args64[SP_MSG_ARG_COUNT];
+ } args;
};
/**
diff --git a/components/messaging/ffa/libsp/mock/component.cmake b/components/messaging/ffa/libsp/mock/component.cmake
new file mode 100644
index 000000000..375cb4665
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/component.cmake
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/mock_assert.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/mock_ffa_api.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/mock_ffa_internal_api.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/mock_sp_discovery.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/mock_sp_memory_management.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/mock_sp_messaging.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/mock_sp_rxtx.cpp"
+ )
+
+target_include_directories(${TGT}
+ PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/../include
+)
+
+target_compile_definitions(${TGT}
+ PUBLIC
+ "ARM64=1"
+) \ No newline at end of file
diff --git a/components/messaging/ffa/libsp/test/mock_assert.cpp b/components/messaging/ffa/libsp/mock/mock_assert.cpp
index f79021a36..f79021a36 100644
--- a/components/messaging/ffa/libsp/test/mock_assert.cpp
+++ b/components/messaging/ffa/libsp/mock/mock_assert.cpp
diff --git a/components/messaging/ffa/libsp/test/mock_assert.h b/components/messaging/ffa/libsp/mock/mock_assert.h
index 33a03d5c4..33a03d5c4 100644
--- a/components/messaging/ffa/libsp/test/mock_assert.h
+++ b/components/messaging/ffa/libsp/mock/mock_assert.h
diff --git a/components/messaging/ffa/libsp/test/mock_ffa_api.cpp b/components/messaging/ffa/libsp/mock/mock_ffa_api.cpp
index cf04c1b38..38637cf93 100644
--- a/components/messaging/ffa/libsp/test/mock_ffa_api.cpp
+++ b/components/messaging/ffa/libsp/mock/mock_ffa_api.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*/
#include <CppUTestExt/MockSupport.h>
@@ -140,13 +140,13 @@ ffa_result ffa_msg_wait(struct ffa_direct_msg *msg)
.returnIntValue();
}
-void expect_ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
- uint32_t a1, uint32_t a2, uint32_t a3,
- uint32_t a4,
- const struct ffa_direct_msg *msg,
- ffa_result result)
+void expect_ffa_msg_send_direct_req_32(uint16_t source, uint16_t dest,
+ uint32_t a0, uint32_t a1, uint32_t a2,
+ uint32_t a3, uint32_t a4,
+ const struct ffa_direct_msg *msg,
+ ffa_result result)
{
- mock().expectOneCall("ffa_msg_send_direct_req")
+ mock().expectOneCall("ffa_msg_send_direct_req_32")
.withUnsignedIntParameter("source", source)
.withUnsignedIntParameter("dest", dest)
.withUnsignedIntParameter("a0", a0)
@@ -158,12 +158,13 @@ void expect_ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
.andReturnValue(result);
}
-ffa_result ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
- uint32_t a1, uint32_t a2, uint32_t a3,
- uint32_t a4, struct ffa_direct_msg *msg)
+ffa_result ffa_msg_send_direct_req_32(uint16_t source, uint16_t dest,
+ uint32_t a0, uint32_t a1, uint32_t a2,
+ uint32_t a3,uint32_t a4,
+ struct ffa_direct_msg *msg)
{
return mock()
- .actualCall("ffa_msg_send_direct_req")
+ .actualCall("ffa_msg_send_direct_req_32")
.withUnsignedIntParameter("source", source)
.withUnsignedIntParameter("dest", dest)
.withUnsignedIntParameter("a0", a0)
@@ -175,13 +176,49 @@ ffa_result ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
.returnIntValue();
}
-void expect_ffa_msg_send_direct_resp(uint16_t source, uint16_t dest,
+void expect_ffa_msg_send_direct_req_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ const struct ffa_direct_msg *msg,
+ ffa_result result)
+{
+ mock().expectOneCall("ffa_msg_send_direct_req_64")
+ .withUnsignedIntParameter("source", source)
+ .withUnsignedIntParameter("dest", dest)
+ .withUnsignedLongIntParameter("a0", a0)
+ .withUnsignedLongIntParameter("a1", a1)
+ .withUnsignedLongIntParameter("a2", a2)
+ .withUnsignedLongIntParameter("a3", a3)
+ .withUnsignedLongIntParameter("a4", a4)
+ .withOutputParameterReturning("msg", msg, sizeof(*msg))
+ .andReturnValue(result);
+}
+
+ffa_result ffa_msg_send_direct_req_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ struct ffa_direct_msg *msg)
+{
+ return mock()
+ .actualCall("ffa_msg_send_direct_req_64")
+ .withUnsignedIntParameter("source", source)
+ .withUnsignedIntParameter("dest", dest)
+ .withUnsignedLongIntParameter("a0", a0)
+ .withUnsignedLongIntParameter("a1", a1)
+ .withUnsignedLongIntParameter("a2", a2)
+ .withUnsignedLongIntParameter("a3", a3)
+ .withUnsignedLongIntParameter("a4", a4)
+ .withOutputParameter("msg", msg)
+ .returnIntValue();
+}
+
+void expect_ffa_msg_send_direct_resp_32(uint16_t source, uint16_t dest,
uint32_t a0, uint32_t a1, uint32_t a2,
uint32_t a3, uint32_t a4,
const struct ffa_direct_msg *msg,
ffa_result result)
{
- mock().expectOneCall("ffa_msg_send_direct_resp")
+ mock().expectOneCall("ffa_msg_send_direct_resp_32")
.withUnsignedIntParameter("source", source)
.withUnsignedIntParameter("dest", dest)
.withUnsignedIntParameter("a0", a0)
@@ -193,12 +230,12 @@ void expect_ffa_msg_send_direct_resp(uint16_t source, uint16_t dest,
.andReturnValue(result);
}
-ffa_result ffa_msg_send_direct_resp(uint16_t source, uint16_t dest, uint32_t a0,
+ffa_result ffa_msg_send_direct_resp_32(uint16_t source, uint16_t dest, uint32_t a0,
uint32_t a1, uint32_t a2, uint32_t a3,
uint32_t a4, struct ffa_direct_msg *msg)
{
return mock()
- .actualCall("ffa_msg_send_direct_resp")
+ .actualCall("ffa_msg_send_direct_resp_32")
.withUnsignedIntParameter("source", source)
.withUnsignedIntParameter("dest", dest)
.withUnsignedIntParameter("a0", a0)
@@ -210,6 +247,41 @@ ffa_result ffa_msg_send_direct_resp(uint16_t source, uint16_t dest, uint32_t a0,
.returnIntValue();
}
+void expect_ffa_msg_send_direct_resp_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ const struct ffa_direct_msg *msg,
+ ffa_result result)
+{
+ mock().expectOneCall("ffa_msg_send_direct_resp_64")
+ .withUnsignedIntParameter("source", source)
+ .withUnsignedIntParameter("dest", dest)
+ .withUnsignedLongIntParameter("a0", a0)
+ .withUnsignedLongIntParameter("a1", a1)
+ .withUnsignedLongIntParameter("a2", a2)
+ .withUnsignedLongIntParameter("a3", a3)
+ .withUnsignedLongIntParameter("a4", a4)
+ .withOutputParameterReturning("msg", msg, sizeof(*msg))
+ .andReturnValue(result);
+}
+
+ffa_result ffa_msg_send_direct_resp_64(uint16_t source, uint16_t dest, uint64_t a0,
+ uint64_t a1, uint64_t a2, uint64_t a3,
+ uint64_t a4, struct ffa_direct_msg *msg)
+{
+ return mock()
+ .actualCall("ffa_msg_send_direct_resp_64")
+ .withUnsignedIntParameter("source", source)
+ .withUnsignedIntParameter("dest", dest)
+ .withUnsignedLongIntParameter("a0", a0)
+ .withUnsignedLongIntParameter("a1", a1)
+ .withUnsignedLongIntParameter("a2", a2)
+ .withUnsignedLongIntParameter("a3", a3)
+ .withUnsignedLongIntParameter("a4", a4)
+ .withOutputParameter("msg", msg)
+ .returnIntValue();
+}
+
void expect_ffa_mem_donate(uint32_t total_length, uint32_t fragment_length,
void *buffer_address, uint32_t page_count,
const uint64_t *handle, ffa_result result)
@@ -451,3 +523,77 @@ ffa_result ffa_mem_reclaim(uint64_t handle, uint32_t flags)
.withUnsignedIntParameter("flags", flags)
.returnIntValue();
}
+
+void expect_ffa_mem_perm_get(const void *base_address, const uint32_t *mem_perm,
+ ffa_result result)
+{
+ mock().expectOneCall("ffa_mem_perm_get")
+ .withConstPointerParameter("base_address", base_address)
+ .withOutputParameterReturning("mem_perm", mem_perm,
+ sizeof(*mem_perm))
+ .andReturnValue(result);
+}
+
+ffa_result ffa_mem_perm_get(const void *base_address, uint32_t *mem_perm)
+{
+ return mock().actualCall("ffa_mem_perm_get")
+ .withConstPointerParameter("base_address", base_address)
+ .withOutputParameter("mem_perm", mem_perm)
+ .returnIntValue();
+}
+
+void expect_ffa_mem_perm_set(const void *base_address, uint32_t page_count,
+ uint32_t mem_perm, ffa_result result)
+{
+ mock().expectOneCall("ffa_mem_perm_set")
+ .withConstPointerParameter("base_address", base_address)
+ .withUnsignedIntParameter("page_count", page_count)
+ .withUnsignedIntParameter("mem_perm", mem_perm)
+ .andReturnValue(result);
+}
+
+ffa_result ffa_mem_perm_set(const void *base_address, uint32_t page_count,
+ uint32_t mem_perm)
+{
+ return mock().actualCall("ffa_mem_perm_set")
+ .withConstPointerParameter("base_address", base_address)
+ .withUnsignedIntParameter("page_count", page_count)
+ .withUnsignedIntParameter("mem_perm", mem_perm)
+ .returnIntValue();
+}
+
+void expect_ffa_console_log_32(const char *message, size_t length,
+ ffa_result result)
+{
+ mock().expectOneCall("ffa_console_log_32")
+ .withStringParameter("message", message)
+ .withUnsignedIntParameter("length", length)
+ .andReturnValue(result);
+}
+
+ffa_result ffa_console_log_32(const char *message, size_t length)
+{
+ return mock()
+ .actualCall("ffa_console_log_32")
+ .withStringParameter("message", message)
+ .withUnsignedIntParameter("length", length)
+ .returnIntValue();
+}
+
+void expect_ffa_console_log_64(const char *message, size_t length,
+ ffa_result result)
+{
+ mock().expectOneCall("ffa_console_log_64")
+ .withStringParameter("message", message)
+ .withUnsignedIntParameter("length", length)
+ .andReturnValue(result);
+}
+
+ffa_result ffa_console_log_64(const char *message, size_t length)
+{
+ return mock()
+ .actualCall("ffa_console_log_64")
+ .withStringParameter("message", message)
+ .withUnsignedIntParameter("length", length)
+ .returnIntValue();
+}
diff --git a/components/messaging/ffa/libsp/test/mock_ffa_api.h b/components/messaging/ffa/libsp/mock/mock_ffa_api.h
index 34a635ce3..9c3dbc84c 100644
--- a/components/messaging/ffa/libsp/test/mock_ffa_api.h
+++ b/components/messaging/ffa/libsp/mock/mock_ffa_api.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*/
#ifndef LIBSP_TEST_MOCK_FFA_API_H_
@@ -30,17 +30,29 @@ void expect_ffa_id_get(const uint16_t *id, ffa_result result);
void expect_ffa_msg_wait(const struct ffa_direct_msg *msg, ffa_result result);
-void expect_ffa_msg_send_direct_req(uint16_t source, uint16_t dest, uint32_t a0,
- uint32_t a1, uint32_t a2, uint32_t a3,
- uint32_t a4,
- const struct ffa_direct_msg *msg,
- ffa_result result);
-
-void expect_ffa_msg_send_direct_resp(uint16_t source, uint16_t dest,
- uint32_t a0, uint32_t a1, uint32_t a2,
- uint32_t a3, uint32_t a4,
- const struct ffa_direct_msg *msg,
- ffa_result result);
+void expect_ffa_msg_send_direct_req_32(uint16_t source, uint16_t dest,
+ uint32_t a0, uint32_t a1, uint32_t a2,
+ uint32_t a3, uint32_t a4,
+ const struct ffa_direct_msg *msg,
+ ffa_result result);
+
+void expect_ffa_msg_send_direct_req_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ const struct ffa_direct_msg *msg,
+ ffa_result result);
+
+void expect_ffa_msg_send_direct_resp_32(uint16_t source, uint16_t dest,
+ uint32_t a0, uint32_t a1, uint32_t a2,
+ uint32_t a3, uint32_t a4,
+ const struct ffa_direct_msg *msg,
+ ffa_result result);
+
+void expect_ffa_msg_send_direct_resp_64(uint16_t source, uint16_t dest,
+ uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t a3, uint64_t a4,
+ const struct ffa_direct_msg *msg,
+ ffa_result result);
void expect_ffa_mem_donate(uint32_t total_length, uint32_t fragment_length,
void *buffer_address, uint32_t page_count,
@@ -80,4 +92,16 @@ void expect_ffa_mem_relinquish(ffa_result result);
void expect_ffa_mem_reclaim(uint64_t handle, uint32_t flags, ffa_result result);
+void expect_ffa_mem_perm_get(const void *base_address, const uint32_t *mem_perm,
+ ffa_result result);
+
+void expect_ffa_mem_perm_set(const void *base_address, uint32_t page_count,
+ uint32_t mem_perm, ffa_result result);
+
+void expect_ffa_console_log_32(const char *message, size_t length,
+ ffa_result result);
+
+void expect_ffa_console_log_64(const char *message, size_t length,
+ ffa_result result);
+
#endif /* FFA_LIBSP_TEST_MOCK_FFA_API_H_ */
diff --git a/components/messaging/ffa/libsp/test/mock_ffa_internal_api.cpp b/components/messaging/ffa/libsp/mock/mock_ffa_internal_api.cpp
index 56b82d89a..56b82d89a 100644
--- a/components/messaging/ffa/libsp/test/mock_ffa_internal_api.cpp
+++ b/components/messaging/ffa/libsp/mock/mock_ffa_internal_api.cpp
diff --git a/components/messaging/ffa/libsp/test/mock_ffa_internal_api.h b/components/messaging/ffa/libsp/mock/mock_ffa_internal_api.h
index d7068960e..d7068960e 100644
--- a/components/messaging/ffa/libsp/test/mock_ffa_internal_api.h
+++ b/components/messaging/ffa/libsp/mock/mock_ffa_internal_api.h
diff --git a/components/messaging/ffa/libsp/mock/mock_sp_discovery.cpp b/components/messaging/ffa/libsp/mock/mock_sp_discovery.cpp
new file mode 100644
index 000000000..6f1830071
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/mock_sp_discovery.cpp
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include "mock_sp_discovery.h"
+
+void expect_sp_discovery_ffa_version_get(const uint16_t *major,
+ const uint16_t *minor,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_discovery_ffa_version_get")
+ .withOutputParameterReturning("major", major, sizeof(*major))
+ .withOutputParameterReturning("minor", minor, sizeof(*minor))
+ .andReturnValue(result);
+}
+
+sp_result sp_discovery_ffa_version_get(uint16_t *major, uint16_t *minor)
+{
+ return mock()
+ .actualCall("sp_discovery_ffa_version_get")
+ .withOutputParameter("major", major)
+ .withOutputParameter("minor", minor)
+ .returnIntValue();
+}
+
+void expect_sp_discovery_own_id_get(const uint16_t *id, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_discovery_own_id_get")
+ .withOutputParameterReturning("id", id, sizeof(*id))
+ .andReturnValue(result);
+}
+
+sp_result sp_discovery_own_id_get(uint16_t *id)
+{
+ return mock()
+ .actualCall("sp_discovery_own_id_get")
+ .withOutputParameter("id", id)
+ .returnIntValue();
+}
+
+void expect_sp_discovery_partition_id_get(const struct sp_uuid *uuid,
+ const uint16_t *id, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_discovery_partition_id_get")
+ .withMemoryBufferParameter("uuid", (const unsigned char *)uuid,
+ sizeof(*uuid))
+ .withOutputParameterReturning("id", id, sizeof(*id))
+ .andReturnValue(result);
+}
+
+sp_result sp_discovery_partition_id_get(const struct sp_uuid *uuid,
+ uint16_t *id)
+{
+ return mock()
+ .actualCall("sp_discovery_partition_id_get")
+ .withMemoryBufferParameter("uuid", (const unsigned char *)uuid,
+ sizeof(*uuid))
+ .withOutputParameter("id", id)
+ .returnIntValue();
+}
+
+void expect_sp_discovery_partition_info_get(const struct sp_uuid *uuid,
+ const struct sp_partition_info *info,
+ uint32_t in_count,
+ const uint32_t *out_count,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_discovery_partition_info_get")
+ .withMemoryBufferParameter("uuid", (const unsigned char *)uuid,
+ sizeof(*uuid))
+ .withOutputParameterReturning("info", info, sizeof(*info))
+ .withUnsignedIntParameter("in_count", in_count)
+ .withOutputParameterReturning("out_count", out_count, sizeof(*out_count))
+ .andReturnValue(result);
+}
+
+sp_result sp_discovery_partition_info_get(const struct sp_uuid *uuid,
+ struct sp_partition_info *info,
+ uint32_t *count)
+{
+ return mock()
+ .actualCall("sp_discovery_partition_info_get")
+ .withMemoryBufferParameter("uuid", (const unsigned char *)uuid,
+ sizeof(*uuid))
+ .withOutputParameter("info", info)
+ .withUnsignedIntParameter("in_count", *count)
+ .withOutputParameter("out_count", count)
+ .returnIntValue();
+}
+
+void expect_sp_discovery_partition_info_get_all(const struct sp_partition_info info[],
+ const uint32_t *count,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_discovery_partition_info_get_all")
+ .withOutputParameterReturning("info", info, sizeof(*info) * *count)
+ .withOutputParameterReturning("count", count, sizeof(*count))
+ .andReturnValue(result);
+}
+
+sp_result sp_discovery_partition_info_get_all(struct sp_partition_info info[],
+ uint32_t *count)
+{
+ return mock()
+ .actualCall("sp_discovery_partition_info_get_all")
+ .withOutputParameter("info", info)
+ .withOutputParameter("count", count)
+ .returnIntValue();
+}
diff --git a/components/messaging/ffa/libsp/mock/mock_sp_discovery.h b/components/messaging/ffa/libsp/mock/mock_sp_discovery.h
new file mode 100644
index 000000000..67cb1186d
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/mock_sp_discovery.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBSP_MOCK_MOCK_SP_DISCOVERY_H_
+#define LIBSP_MOCK_MOCK_SP_DISCOVERY_H_
+
+#include "../include/sp_discovery.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void expect_sp_discovery_ffa_version_get(const uint16_t *major,
+ const uint16_t *minor,
+ sp_result result);
+
+void expect_sp_discovery_own_id_get(const uint16_t *id, sp_result result);
+
+void expect_sp_discovery_partition_id_get(const struct sp_uuid *uuid,
+ const uint16_t *id, sp_result result);
+
+
+void expect_sp_discovery_partition_info_get(const struct sp_uuid *uuid,
+ const struct sp_partition_info *info,
+ uint32_t in_count,
+ const uint32_t *out_count,
+ sp_result result);
+
+void expect_sp_discovery_partition_info_get_all(const struct sp_partition_info info[],
+ const uint32_t *count,
+ sp_result result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSP_MOCK_MOCK_SP_DISCOVERY_H_ */
diff --git a/components/messaging/ffa/libsp/mock/mock_sp_memory_management.cpp b/components/messaging/ffa/libsp/mock/mock_sp_memory_management.cpp
new file mode 100644
index 000000000..9eb0aaa2a
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/mock_sp_memory_management.cpp
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include "mock_sp_memory_management.h"
+
+void expect_sp_memory_donate(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor *acc_desc,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_donate")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc))
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameterReturning("handle", handle, sizeof(*handle))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_donate(struct sp_memory_descriptor *descriptor,
+ struct sp_memory_access_descriptor *acc_desc,
+ struct sp_memory_region regions[],
+ uint32_t region_count, uint64_t *handle)
+{
+ return mock()
+ .actualCall("sp_memory_donate")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc))
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameter("handle", handle)
+ .returnIntValue();
+}
+
+void expect_sp_memory_donate_dynamic(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor *acc_desc,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_donate_dynamic")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc))
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameterReturning("handle", handle, sizeof(*handle))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_donate_dynamic(struct sp_memory_descriptor *descriptor,
+ struct sp_memory_access_descriptor *acc_desc,
+ struct sp_memory_region regions[],
+ uint32_t region_count, uint64_t *handle,
+ struct ffa_mem_transaction_buffer *buffer)
+{
+ if (buffer == NULL) { // LCOV_EXCL_BR_LINE
+ FAIL("ffa_mem_transaction_buffer is NULL"); // LCOV_EXCL_LINE
+ }
+
+ return mock()
+ .actualCall("sp_memory_donate_dynamic")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc))
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameter("handle", handle)
+ .returnIntValue();
+}
+
+void expect_sp_memory_donate_dynamic_is_supported(const bool *supported, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_lend_dynamic_is_supported")
+ .withOutputParameterReturning("supported", supported, sizeof(*supported))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_donate_dynamic_is_supported(bool *supported)
+{
+ return mock()
+ .actualCall("sp_memory_lend_dynamic_is_supported")
+ .withOutputParameter("supported", supported)
+ .returnIntValue();
+}
+
+void expect_sp_memory_lend(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_lend")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc) * acc_desc_count)
+ .withUnsignedIntParameter("acc_desc_count", acc_desc_count)
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameterReturning("handle", handle, sizeof(*handle))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_lend(struct sp_memory_descriptor *descriptor,
+ struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ struct sp_memory_region regions[],
+ uint32_t region_count, uint64_t *handle)
+{
+ return mock()
+ .actualCall("sp_memory_lend")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc) * acc_desc_count)
+ .withUnsignedIntParameter("acc_desc_count", acc_desc_count)
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameter("handle", handle)
+ .returnIntValue();
+}
+
+void expect_sp_memory_lend_dynamic(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ const struct sp_memory_region regions[],
+ const uint32_t region_count, const uint64_t *handle,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_lend")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc) * acc_desc_count)
+ .withUnsignedIntParameter("acc_desc_count", acc_desc_count)
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameterReturning("handle", handle, sizeof(*handle))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_lend_dynamic(struct sp_memory_descriptor *descriptor,
+ struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ struct sp_memory_region regions[],
+ uint32_t region_count, uint64_t *handle,
+ struct ffa_mem_transaction_buffer *buffer)
+{
+ if (buffer == NULL) { // LCOV_EXCL_BR_LINE
+ FAIL("ffa_mem_transaction_buffer is NULL"); // LCOV_EXCL_LINE
+ }
+
+ return mock()
+ .actualCall("sp_memory_lend")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc) * acc_desc_count)
+ .withUnsignedIntParameter("acc_desc_count", acc_desc_count)
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameter("handle", handle)
+ .returnIntValue();
+}
+
+void expect_sp_memory_lend_dynamic_is_supported(const bool *supported, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_lend_dynamic_is_supported")
+ .withOutputParameterReturning("supported", supported, sizeof(*supported))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_lend_dynamic_is_supported(bool *supported)
+{
+ return mock()
+ .actualCall("sp_memory_lend_dynamic_is_supported")
+ .withOutputParameter("supported", supported)
+ .returnIntValue();
+}
+
+void expect_sp_memory_share(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_share")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc) * acc_desc_count)
+ .withUnsignedIntParameter("acc_desc_count", acc_desc_count)
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameterReturning("handle", handle, sizeof(*handle))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_share(struct sp_memory_descriptor *descriptor,
+ struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ struct sp_memory_region regions[],
+ uint32_t region_count, uint64_t *handle)
+{
+ return mock()
+ .actualCall("sp_memory_share")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc) * acc_desc_count)
+ .withUnsignedIntParameter("acc_desc_count", acc_desc_count)
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameter("handle", handle)
+ .returnIntValue();
+}
+
+void expect_sp_memory_share_dynamic(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_share_dynamic")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc) * acc_desc_count)
+ .withUnsignedIntParameter("acc_desc_count", acc_desc_count)
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameterReturning("handle", handle, sizeof(*handle))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_share_dynamic(struct sp_memory_descriptor *descriptor,
+ struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ struct sp_memory_region regions[],
+ uint32_t region_count, uint64_t *handle,
+ struct ffa_mem_transaction_buffer *buffer)
+{
+ if (buffer == NULL) { // LCOV_EXCL_BR_LINE
+ FAIL("ffa_mem_transaction_buffer is NULL"); // LCOV_EXCL_LINE
+ }
+
+ return mock()
+ .actualCall("sp_memory_share_dynamic")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(*descriptor))
+ .withMemoryBufferParameter("acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc) * acc_desc_count)
+ .withUnsignedIntParameter("acc_desc_count", acc_desc_count)
+ .withMemoryBufferParameter("regions", (const unsigned char *)regions,
+ sizeof(*regions) * region_count)
+ .withUnsignedIntParameter("region_count", region_count)
+ .withOutputParameter("handle", handle)
+ .returnIntValue();
+}
+
+void expect_sp_memory_share_dynamic_is_supported(const bool *supported, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_share_dynamic_is_supported")
+ .withOutputParameterReturning("supported", supported, sizeof(*supported))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_share_dynamic_is_supported(bool *supported)
+{
+ return mock()
+ .actualCall("sp_memory_share_dynamic_is_supported")
+ .withOutputParameter("supported", supported)
+ .returnIntValue();
+}
+
+void expect_sp_memory_retrieve(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor *req_acc_desc,
+ const struct sp_memory_access_descriptor *resp_acc_desc,
+ const struct sp_memory_region in_regions[],
+ const struct sp_memory_region out_regions[],
+ uint32_t in_region_count,
+ const uint32_t *out_region_count, uint64_t handle,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_retrieve")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(descriptor))
+ .withMemoryBufferParameter("req_acc_desc", (const unsigned char *)req_acc_desc,
+ sizeof(*req_acc_desc))
+ .withOutputParameterReturning("resp_acc_desc",
+ (const unsigned char *)resp_acc_desc,
+ sizeof(*resp_acc_desc))
+ .withMemoryBufferParameter("in_regions", (const unsigned char *)in_regions,
+ sizeof(*in_regions) * in_region_count)
+ .withOutputParameterReturning("out_regions", out_regions,
+ sizeof(*out_regions) * *out_region_count)
+ .withUnsignedIntParameter("in_region_count", in_region_count)
+ .withOutputParameterReturning("out_region_count", out_region_count,
+ sizeof(*out_region_count))
+ .withUnsignedLongIntParameter("handle", handle)
+ .andReturnValue(result);
+
+}
+
+sp_result sp_memory_retrieve(struct sp_memory_descriptor *descriptor,
+ struct sp_memory_access_descriptor *acc_desc,
+ struct sp_memory_region regions[],
+ uint32_t in_region_count,
+ uint32_t *out_region_count, uint64_t handle)
+{
+ return mock()
+ .actualCall("sp_memory_retrieve")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(descriptor))
+ .withMemoryBufferParameter("req_acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc))
+ .withOutputParameter("resp_acc_desc", acc_desc)
+ .withMemoryBufferParameter("in_regions", (const unsigned char *)regions,
+ sizeof(*regions) * in_region_count)
+ .withOutputParameter("out_regions", regions)
+ .withUnsignedIntParameter("in_region_count", in_region_count)
+ .withOutputParameter("out_region_count", out_region_count)
+ .withUnsignedLongIntParameter("handle", handle)
+ .returnIntValue();
+}
+
+void expect_sp_memory_retrieve_dynamic(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor *req_acc_desc,
+ const struct sp_memory_access_descriptor *resp_acc_desc,
+ const struct sp_memory_region in_regions[],
+ const struct sp_memory_region out_regions[],
+ uint32_t in_region_count,
+ const uint32_t *out_region_count, uint64_t handle,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_retrieve")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(descriptor))
+ .withMemoryBufferParameter("req_acc_desc", (const unsigned char *)req_acc_desc,
+ sizeof(*req_acc_desc))
+ .withOutputParameterReturning("resp_acc_desc",
+ (const unsigned char *)resp_acc_desc,
+ sizeof(*resp_acc_desc))
+ .withMemoryBufferParameter("in_regions", (const unsigned char *)in_regions,
+ sizeof(*in_regions) * in_region_count)
+ .withOutputParameterReturning("out_regions", out_regions,
+ sizeof(*out_regions) * *out_region_count)
+ .withUnsignedIntParameter("in_region_count", in_region_count)
+ .withOutputParameterReturning("out_region_count", out_region_count,
+ sizeof(*out_region_count))
+ .withUnsignedLongIntParameter("handle", handle)
+ .andReturnValue(result);
+}
+
+sp_result
+sp_memory_retrieve_dynamic(struct sp_memory_descriptor *descriptor,
+ struct sp_memory_access_descriptor *acc_desc,
+ struct sp_memory_region regions[],
+ uint32_t in_region_count, uint32_t *out_region_count,
+ uint64_t handle,
+ struct ffa_mem_transaction_buffer *buffer)
+{
+ if (buffer == NULL) { // LCOV_EXCL_BR_LINE
+ FAIL("ffa_mem_transaction_buffer is NULL"); // LCOV_EXCL_LINE
+ }
+
+ return mock()
+ .actualCall("sp_memory_retrieve")
+ .withMemoryBufferParameter("descriptor", (const unsigned char *)descriptor,
+ sizeof(descriptor))
+ .withMemoryBufferParameter("req_acc_desc", (const unsigned char *)acc_desc,
+ sizeof(*acc_desc))
+ .withOutputParameter("resp_acc_desc", acc_desc)
+ .withMemoryBufferParameter("in_regions", (const unsigned char *)regions,
+ sizeof(*regions) * in_region_count)
+ .withOutputParameter("out_regions", regions)
+ .withUnsignedIntParameter("in_region_count", in_region_count)
+ .withOutputParameter("out_region_count", out_region_count)
+ .withUnsignedLongIntParameter("handle", handle)
+ .returnIntValue();
+}
+
+void expect_sp_memory_retrieve_dynamic_is_supported(const bool *supported, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_retrieve_dynamic_is_supported")
+ .withOutputParameterReturning("supported", supported, sizeof(*supported))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_retrieve_dynamic_is_supported(bool *supported)
+{
+ return mock()
+ .actualCall("sp_memory_retrieve_dynamic_is_supported")
+ .withOutputParameter("supported", supported)
+ .returnIntValue();
+}
+
+void expect_sp_memory_relinquish(uint64_t handle, const uint16_t endpoints[],
+ uint32_t endpoint_count,
+ const struct sp_memory_transaction_flags *flags,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_relinquish")
+ .withUnsignedLongIntParameter("handle", handle)
+ .withMemoryBufferParameter("endpoints", (const unsigned char *)endpoints,
+ sizeof(*endpoints) * endpoint_count)
+ .withMemoryBufferParameter("flags", (const unsigned char *)flags, sizeof(*flags))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_relinquish(uint64_t handle, const uint16_t endpoints[],
+ uint32_t endpoint_count,
+ struct sp_memory_transaction_flags *flags)
+{
+ return mock()
+ .actualCall("sp_memory_relinquish")
+ .withUnsignedLongIntParameter("handle", handle)
+ .withMemoryBufferParameter("endpoints", (const unsigned char *)endpoints,
+ sizeof(*endpoints) * endpoint_count)
+ .withMemoryBufferParameter("flags", (const unsigned char *)flags, sizeof(*flags))
+ .returnIntValue();
+}
+
+void expect_sp_memory_reclaim(uint64_t handle, uint32_t flags, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_reclaim")
+ .withUnsignedLongIntParameter("handle", handle)
+ .withUnsignedIntParameter("flags", flags)
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_reclaim(uint64_t handle, uint32_t flags)
+{
+ return mock()
+ .actualCall("sp_memory_reclaim")
+ .withUnsignedLongIntParameter("handle", handle)
+ .withUnsignedIntParameter("flags", flags)
+ .returnIntValue();
+}
+
+void expect_sp_memory_permission_get(const void *base_address, const struct sp_mem_perm *mem_perm,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_permission_set")
+ .withConstPointerParameter("base_address", base_address)
+ .withOutputParameterReturning("mem_perm", mem_perm,
+ sizeof(*mem_perm))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_permission_get(const void *base_address,
+ struct sp_mem_perm *mem_perm)
+{
+ return mock()
+ .actualCall("sp_memory_permission_set")
+ .withConstPointerParameter("base_address", base_address)
+ .withOutputParameter("mem_perm", mem_perm)
+ .returnIntValue();
+}
+
+void expect_sp_memory_permission_set(const void *base_address, size_t region_size,
+ const struct sp_mem_perm *mem_perm, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_memory_permission_set")
+ .withConstPointerParameter("base_address", base_address)
+ .withUnsignedLongIntParameter("region_size", region_size)
+ .withMemoryBufferParameter("mem_perm", (const unsigned char *)mem_perm,
+ sizeof(*mem_perm))
+ .andReturnValue(result);
+}
+
+sp_result sp_memory_permission_set(const void *base_address, size_t region_size,
+ const struct sp_mem_perm *mem_perm)
+{
+ return mock()
+ .actualCall("sp_memory_permission_set")
+ .withConstPointerParameter("base_address", base_address)
+ .withUnsignedLongIntParameter("region_size", region_size)
+ .withMemoryBufferParameter("mem_perm", (const unsigned char *)mem_perm,
+ sizeof(*mem_perm))
+ .returnIntValue();
+}
diff --git a/components/messaging/ffa/libsp/mock/mock_sp_memory_management.h b/components/messaging/ffa/libsp/mock/mock_sp_memory_management.h
new file mode 100644
index 000000000..458d2af89
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/mock_sp_memory_management.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBSP_MOCK_MOCK_SP_MEMORY_MANAGEMENT_H_
+#define LIBSP_MOCK_MOCK_SP_MEMORY_MANAGEMENT_H_
+
+#include "../include/sp_memory_management.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void expect_sp_memory_donate(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor *acc_desc,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result);
+
+void expect_sp_memory_donate_dynamic(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor *acc_desc,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result);
+
+void expect_sp_memory_donate_dynamic_is_supported(const bool *supported, sp_result result);
+
+void expect_sp_memory_lend(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result);
+
+void expect_sp_memory_lend_dynamic(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ const struct sp_memory_region regions[],
+ const uint32_t region_count, const uint64_t *handle,
+ sp_result result);
+
+void expect_sp_memory_lend_dynamic_is_supported(const bool *supported, sp_result result);
+
+void expect_sp_memory_share(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result);
+
+void expect_sp_memory_share_dynamic(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor acc_desc[],
+ uint32_t acc_desc_count,
+ const struct sp_memory_region regions[],
+ uint32_t region_count, const uint64_t *handle,
+ sp_result result);
+
+void expect_sp_memory_share_dynamic_is_supported(const bool *supported, sp_result result);
+
+void expect_sp_memory_retrieve(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor *req_acc_desc,
+ const struct sp_memory_access_descriptor *resp_acc_desc,
+ const struct sp_memory_region in_regions[],
+ const struct sp_memory_region out_regions[],
+ uint32_t in_region_count,
+ const uint32_t *out_region_count, uint64_t handle,
+ sp_result result);
+
+void expect_sp_memory_retrieve_dynamic(const struct sp_memory_descriptor *descriptor,
+ const struct sp_memory_access_descriptor *req_acc_desc,
+ const struct sp_memory_access_descriptor *resp_acc_desc,
+ const struct sp_memory_region in_regions[],
+ const struct sp_memory_region out_regions[],
+ uint32_t in_region_count,
+ const uint32_t *out_region_count, uint64_t handle,
+ sp_result result);
+
+void expect_sp_memory_retrieve_dynamic_is_supported(const bool *supported, sp_result result);
+
+void expect_sp_memory_relinquish(uint64_t handle, const uint16_t endpoints[],
+ uint32_t endpoint_count,
+ const struct sp_memory_transaction_flags *flags,
+ sp_result result);
+
+void expect_sp_memory_reclaim(uint64_t handle, uint32_t flags, sp_result result);
+
+void expect_sp_memory_permission_get(const void *base_address, const struct sp_mem_perm *mem_perm,
+ sp_result result);
+
+void expect_sp_memory_permission_set(const void *base_address, size_t region_size,
+ const struct sp_mem_perm *mem_perm, sp_result result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSP_MOCK_MOCK_SP_MEMORY_MANAGEMENT_H_ */
diff --git a/components/messaging/ffa/libsp/mock/mock_sp_messaging.cpp b/components/messaging/ffa/libsp/mock/mock_sp_messaging.cpp
new file mode 100644
index 000000000..522abb36a
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/mock_sp_messaging.cpp
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include "mock_sp_messaging.h"
+
+void expect_sp_msg_wait(const struct sp_msg *msg, sp_result result)
+{
+ mock()
+ .expectOneCall("sp_msg_wait")
+ .withOutputParameterReturning("msg", msg, sizeof(*msg))
+ .andReturnValue(result);
+}
+
+sp_result sp_msg_wait(struct sp_msg *msg)
+{
+ return mock()
+ .actualCall("sp_msg_wait")
+ .withOutputParameter("msg", msg)
+ .returnIntValue();
+}
+
+void expect_sp_msg_send_direct_req(const struct sp_msg *req,
+ const struct sp_msg *resp,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_msg_send_direct_req")
+ .withMemoryBufferParameter("req", (const unsigned char *)req, sizeof(*req))
+ .withOutputParameterReturning("resp", resp, sizeof(*resp))
+ .andReturnValue(result);
+}
+
+sp_result sp_msg_send_direct_req(const struct sp_msg *req, struct sp_msg *resp)
+{
+ return mock()
+ .actualCall("sp_msg_send_direct_req")
+ .withMemoryBufferParameter("req", (const unsigned char *)req, sizeof(*req))
+ .withOutputParameter("resp", resp)
+ .returnIntValue();
+}
+
+void expect_sp_msg_send_direct_resp(const struct sp_msg *resp,
+ const struct sp_msg *req,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_msg_send_direct_resp")
+ .withMemoryBufferParameter("resp", (const unsigned char *)resp, sizeof(*resp))
+ .withOutputParameterReturning("req", req, sizeof(*req))
+ .andReturnValue(result);
+}
+
+sp_result sp_msg_send_direct_resp(const struct sp_msg *resp,
+ struct sp_msg *req)
+{
+ return mock()
+ .actualCall("sp_msg_send_direct_resp")
+ .withMemoryBufferParameter("resp", (const unsigned char *)resp, sizeof(*resp))
+ .withOutputParameter("req", req)
+ .returnIntValue();
+}
+
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+void expect_sp_msg_send_rc_req(const struct sp_msg *req,
+ const struct sp_msg *resp,
+ sp_result result)
+{
+ mock()
+ .expectOneCall("sp_msg_send_rc_req")
+ .withMemoryBufferParameter("req", (const unsigned char *)req, sizeof(*req))
+ .withOutputParameterReturning("resp", resp, sizeof(*resp))
+ .andReturnValue(result);
+}
+
+sp_result sp_msg_send_rc_req(const struct sp_msg *req, struct sp_msg *resp)
+{
+ return mock()
+ .actualCall("sp_msg_send_rc_req")
+ .withMemoryBufferParameter("req", (const unsigned char *)req, sizeof(*req))
+ .withOutputParameter("resp", resp)
+ .returnIntValue();
+}
+#endif /* FFA_DIRECT_MSG_ROUTING_EXTENSION */
diff --git a/components/messaging/ffa/libsp/mock/mock_sp_messaging.h b/components/messaging/ffa/libsp/mock/mock_sp_messaging.h
new file mode 100644
index 000000000..8183012e5
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/mock_sp_messaging.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBSP_MOCK_MOCK_SP_MESSAGING_H_
+#define LIBSP_MOCK_MOCK_SP_MESSAGING_H_
+
+#include "../include/sp_messaging.h"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void expect_sp_msg_wait(const struct sp_msg *msg, sp_result result);
+
+
+void expect_sp_msg_send_direct_req(const struct sp_msg *req,
+ const struct sp_msg *resp,
+ sp_result result);
+
+
+void expect_sp_msg_send_direct_resp(const struct sp_msg *resp,
+ const struct sp_msg *req,
+ sp_result result);
+
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+void expect_sp_msg_send_rc_req(const struct sp_msg *req,
+ const struct sp_msg *resp,
+ sp_result result);
+#endif /* FFA_DIRECT_MSG_ROUTING_EXTENSION */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSP_MOCK_MOCK_SP_MESSAGING_H_ */
diff --git a/components/messaging/ffa/libsp/test/mock_sp_rxtx.cpp b/components/messaging/ffa/libsp/mock/mock_sp_rxtx.cpp
index 24111b8c4..24111b8c4 100644
--- a/components/messaging/ffa/libsp/test/mock_sp_rxtx.cpp
+++ b/components/messaging/ffa/libsp/mock/mock_sp_rxtx.cpp
diff --git a/components/messaging/ffa/libsp/test/mock_sp_rxtx.h b/components/messaging/ffa/libsp/mock/mock_sp_rxtx.h
index c036d3628..c036d3628 100644
--- a/components/messaging/ffa/libsp/test/mock_sp_rxtx.h
+++ b/components/messaging/ffa/libsp/mock/mock_sp_rxtx.h
diff --git a/components/messaging/ffa/libsp/test/test_mock_assert.cpp b/components/messaging/ffa/libsp/mock/test/test_mock_assert.cpp
index 39004d645..39004d645 100644
--- a/components/messaging/ffa/libsp/test/test_mock_assert.cpp
+++ b/components/messaging/ffa/libsp/mock/test/test_mock_assert.cpp
diff --git a/components/messaging/ffa/libsp/test/test_mock_ffa_api.cpp b/components/messaging/ffa/libsp/mock/test/test_mock_ffa_api.cpp
index 15b266a54..8b793d332 100644
--- a/components/messaging/ffa/libsp/test/test_mock_ffa_api.cpp
+++ b/components/messaging/ffa/libsp/mock/test/test_mock_ffa_api.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*/
#include <assert.h>
@@ -105,7 +105,7 @@ TEST(mock_ffa_api, ffa_msg_wait)
MEMCMP_EQUAL(&expected_msg, &msg, sizeof(expected_msg));
}
-TEST(mock_ffa_api, ffa_msg_send_direct_req)
+TEST(mock_ffa_api, ffa_msg_send_direct_req_32)
{
const uint16_t source = 0x1122;
const uint16_t dest = 0x2233;
@@ -116,13 +116,30 @@ TEST(mock_ffa_api, ffa_msg_send_direct_req)
const uint32_t a4 = 0x89124567;
struct ffa_direct_msg msg = { 0 };
- expect_ffa_msg_send_direct_req(source, dest, a0, a1, a2, a3, a4,
+ expect_ffa_msg_send_direct_req_32(source, dest, a0, a1, a2, a3, a4,
+ &expected_msg, result);
+ LONGS_EQUAL(result, ffa_msg_send_direct_req_32(source, dest, a0, a1, a2,
+ a3, a4, &msg));
+}
+
+TEST(mock_ffa_api, ffa_msg_send_direct_req_64)
+{
+ const uint16_t source = 0x1122;
+ const uint16_t dest = 0x2233;
+ const uint64_t a0 = 0x4567891221987654;
+ const uint64_t a1 = 0x5678912442198765;
+ const uint64_t a2 = 0x6789124554219876;
+ const uint64_t a3 = 0x7891245665421987;
+ const uint64_t a4 = 0x8912456776542198;
+ struct ffa_direct_msg msg = { 0 };
+
+ expect_ffa_msg_send_direct_req_64(source, dest, a0, a1, a2, a3, a4,
&expected_msg, result);
- LONGS_EQUAL(result, ffa_msg_send_direct_req(source, dest, a0, a1, a2,
- a3, a4, &msg));
+ LONGS_EQUAL(result, ffa_msg_send_direct_req_64(source, dest, a0, a1, a2,
+ a3, a4, &msg));
}
-TEST(mock_ffa_api, ffa_msg_send_direct_resp)
+TEST(mock_ffa_api, ffa_msg_send_direct_resp_32)
{
const uint16_t source = 0x1122;
const uint16_t dest = 0x2233;
@@ -133,10 +150,27 @@ TEST(mock_ffa_api, ffa_msg_send_direct_resp)
const uint32_t a4 = 0x89124567;
struct ffa_direct_msg msg = { 0 };
- expect_ffa_msg_send_direct_resp(source, dest, a0, a1, a2, a3, a4,
+ expect_ffa_msg_send_direct_resp_32(source, dest, a0, a1, a2, a3, a4,
&expected_msg, result);
- LONGS_EQUAL(result, ffa_msg_send_direct_resp(source, dest, a0, a1, a2,
- a3, a4, &msg));
+ LONGS_EQUAL(result, ffa_msg_send_direct_resp_32(source, dest, a0, a1,
+ a2, a3, a4, &msg));
+}
+
+TEST(mock_ffa_api, ffa_msg_send_direct_resp_64)
+{
+ const uint16_t source = 0x1122;
+ const uint16_t dest = 0x2233;
+ const uint64_t a0 = 0x4567891221987654;
+ const uint64_t a1 = 0x5678912442198765;
+ const uint64_t a2 = 0x6789124554219876;
+ const uint64_t a3 = 0x7891245665421987;
+ const uint64_t a4 = 0x8912456776542198;
+ struct ffa_direct_msg msg = { 0 };
+
+ expect_ffa_msg_send_direct_resp_64(source, dest, a0, a1, a2, a3, a4,
+ &expected_msg, result);
+ LONGS_EQUAL(result, ffa_msg_send_direct_resp_64(source, dest, a0, a1,
+ a2, a3, a4, &msg));
}
TEST(mock_ffa_api, ffa_mem_donate)
@@ -290,3 +324,42 @@ TEST(mock_ffa_api, ffa_mem_reclaim)
expect_ffa_mem_reclaim(handle, flags, result);
LONGS_EQUAL(result, ffa_mem_reclaim(handle, flags));
}
+
+TEST(mock_ffa_api, ffa_mem_perm_get)
+{
+ const void *base_address = (const void *)0x01234567;
+ uint32_t expected_mem_perm = 0x89abcdef;
+ uint32_t mem_perm = 0;
+
+ expect_ffa_mem_perm_get(base_address, &expected_mem_perm, result);
+ LONGS_EQUAL(result, ffa_mem_perm_get(base_address, &mem_perm));
+ UNSIGNED_LONGS_EQUAL(expected_mem_perm, mem_perm);
+}
+
+TEST(mock_ffa_api, ffa_mem_perm_set)
+{
+ const void *base_address = (const void *)0x01234567;
+ const uint32_t page_count = 0x76543210;
+ const uint32_t mem_perm = 0x89abcdef;
+
+ expect_ffa_mem_perm_set(base_address, page_count, mem_perm, result);
+ LONGS_EQUAL(result, ffa_mem_perm_set(base_address, page_count, mem_perm));
+}
+
+TEST(mock_ffa_api, ffa_console_log_32)
+{
+ const char *message = "log message";
+ const size_t length = 11;
+
+ expect_ffa_console_log_32(message, length, result);
+ LONGS_EQUAL(result, ffa_console_log_32(message, length));
+}
+
+TEST(mock_ffa_api, ffa_console_log_64)
+{
+ const char *message = "log message";
+ const size_t length = 11;
+
+ expect_ffa_console_log_64(message, length, result);
+ LONGS_EQUAL(result, ffa_console_log_64(message, length));
+}
diff --git a/components/messaging/ffa/libsp/test/test_mock_ffa_internal_api.cpp b/components/messaging/ffa/libsp/mock/test/test_mock_ffa_internal_api.cpp
index ca0760665..ca0760665 100644
--- a/components/messaging/ffa/libsp/test/test_mock_ffa_internal_api.cpp
+++ b/components/messaging/ffa/libsp/mock/test/test_mock_ffa_internal_api.cpp
diff --git a/components/messaging/ffa/libsp/mock/test/test_mock_sp_discovery.cpp b/components/messaging/ffa/libsp/mock/test/test_mock_sp_discovery.cpp
new file mode 100644
index 000000000..5b6c538c8
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/test/test_mock_sp_discovery.cpp
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include <CppUTest/TestHarness.h>
+#include "mock_sp_discovery.h"
+#include <stdint.h>
+#include <stdlib.h>
+
+
+
+
+TEST_GROUP(mock_sp_discovery) {
+ TEST_TEARDOWN()
+ {
+ mock().checkExpectations();
+ mock().clear();
+ }
+
+ static const sp_result result = -1;
+};
+
+TEST(mock_sp_discovery, sp_discovery_ffa_version_get)
+{
+ const uint16_t expected_major = 0xabcd;
+ const uint16_t expected_minor = 0xef01;
+ uint16_t major = 0, minor = 0;
+
+ expect_sp_discovery_ffa_version_get(&expected_major, &expected_minor,
+ result);
+ LONGS_EQUAL(result, sp_discovery_ffa_version_get(&major, &minor));
+ UNSIGNED_LONGS_EQUAL(expected_major, major);
+ UNSIGNED_LONGS_EQUAL(expected_minor, minor);
+}
+
+TEST(mock_sp_discovery, sp_discovery_own_id_get)
+{
+ const uint16_t expected_id = 0x8765;
+ uint16_t id = 0;
+
+ expect_sp_discovery_own_id_get(&expected_id, result);
+ LONGS_EQUAL(result, sp_discovery_own_id_get(&id));
+ UNSIGNED_LONGS_EQUAL(expected_id, id);
+}
+
+TEST(mock_sp_discovery, sp_discovery_partition_id_get)
+{
+ const struct sp_uuid expected_uuid = {
+ .uuid = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}};
+ const uint16_t expected_id = 0xc1ca;
+
+ struct sp_uuid uuid = expected_uuid;
+ uint16_t id = 0;
+
+ expect_sp_discovery_partition_id_get(&expected_uuid, &expected_id,
+ result);
+ LONGS_EQUAL(result, sp_discovery_partition_id_get(&uuid, &id));
+ UNSIGNED_LONGS_EQUAL(expected_id, id);
+}
+
+TEST(mock_sp_discovery, sp_discovery_partition_info_get)
+{
+ const struct sp_uuid expected_uuid = {
+ .uuid = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}};
+ const struct sp_partition_info expected_info = {
+ .partition_id = 0x1234,
+ .execution_context_count = 0xffff,
+ .supports_direct_requests = true,
+ .can_send_direct_requests = true,
+ .supports_indirect_requests = false
+ };
+
+ struct sp_uuid uuid = expected_uuid;
+ struct sp_partition_info info = {0};
+ uint32_t in_count = 16;
+ uint32_t expected_out_count = 8;
+ uint32_t out_count = in_count;
+
+
+ expect_sp_discovery_partition_info_get(&expected_uuid, &expected_info,
+ in_count, &expected_out_count,
+ result);
+ LONGS_EQUAL(result, sp_discovery_partition_info_get(&uuid, &info, &out_count));
+ MEMCMP_EQUAL(&expected_info, &info, sizeof(&expected_info));
+ UNSIGNED_LONGS_EQUAL(expected_out_count, out_count);
+}
+
+TEST(mock_sp_discovery, sp_discovery_partition_info_get_all)
+{
+ const uint32_t expected_count = 2;
+ const struct sp_partition_info expected_info[expected_count] = {{
+ .partition_id = 0x5678,
+ .execution_context_count = 0x1111,
+ .supports_direct_requests = false,
+ .can_send_direct_requests = false,
+ .supports_indirect_requests = true
+ }, {
+ .partition_id = 0x1234,
+ .execution_context_count = 0xffff,
+ .supports_direct_requests = true,
+ .can_send_direct_requests = true,
+ .supports_indirect_requests = false
+ }};
+
+ struct sp_partition_info info[expected_count] = {0};
+ uint32_t count = 0;
+
+ expect_sp_discovery_partition_info_get_all(expected_info,
+ &expected_count, result);
+ LONGS_EQUAL(result, sp_discovery_partition_info_get_all(info, &count));
+ MEMCMP_EQUAL(&expected_info, &info, sizeof(&expected_info));
+ UNSIGNED_LONGS_EQUAL(expected_count, count);
+} \ No newline at end of file
diff --git a/components/messaging/ffa/libsp/mock/test/test_mock_sp_messaging.cpp b/components/messaging/ffa/libsp/mock/test/test_mock_sp_messaging.cpp
new file mode 100644
index 000000000..02d12a689
--- /dev/null
+++ b/components/messaging/ffa/libsp/mock/test/test_mock_sp_messaging.cpp
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include <CppUTest/TestHarness.h>
+#include "mock_sp_messaging.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const struct sp_msg expected_req = {
+ .source_id = 0x0123,
+ .destination_id = 0x4567,
+ .is_64bit_message = false,
+ .args = {0x89abcdef, 0xfedcba98, 0x76543210, 0xabcdef01}
+};
+static const struct sp_msg expected_resp = {
+ .source_id = 0x1234,
+ .destination_id = 0x5678,
+ .is_64bit_message = false,
+ .args = {0x9abcdef8, 0xedcba98f, 0x65432107, 0xbcdef01a}
+};
+
+TEST_GROUP(mock_sp_messaging)
+{
+ TEST_SETUP()
+ {
+ memset(&req, 0x00, sizeof(req));
+ memset(&resp, 0x00, sizeof(resp));
+ }
+
+ TEST_TEARDOWN()
+ {
+ mock().checkExpectations();
+ mock().clear();
+ }
+
+ struct sp_msg req;
+ struct sp_msg resp;
+ static const sp_result result = -1;
+};
+
+TEST(mock_sp_messaging, sp_msg_wait)
+{
+ expect_sp_msg_wait(&expected_req, result);
+ LONGS_EQUAL(result, sp_msg_wait(&req));
+ MEMCMP_EQUAL(&expected_req, &req, sizeof(expected_req));
+}
+
+TEST(mock_sp_messaging, sp_msg_send_direct_req)
+{
+ req = expected_req;
+
+ expect_sp_msg_send_direct_req(&expected_req, &expected_resp, result);
+ LONGS_EQUAL(result, sp_msg_send_direct_req(&req, &resp));
+ MEMCMP_EQUAL(&expected_resp, &resp, sizeof(expected_resp));
+}
+
+TEST(mock_sp_messaging, sp_msg_send_direct_resp)
+{
+ resp = expected_resp;
+
+ expect_sp_msg_send_direct_resp(&expected_resp, &expected_req, result);
+ LONGS_EQUAL(result, sp_msg_send_direct_resp(&resp, &req));
+ MEMCMP_EQUAL(&expected_req, &req, sizeof(expected_req));
+}
+
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+TEST(mock_sp_messaging, sp_msg_send_rc_req)
+{
+ req = expected_req;
+
+ expect_sp_msg_send_rc_req(&expected_req, &expected_resp, result);
+ LONGS_EQUAL(result, sp_msg_send_rc_req(&req, &resp));
+ MEMCMP_EQUAL(&expected_resp, &resp, sizeof(expected_resp));
+}
+#endif /* FFA_DIRECT_MSG_ROUTING_EXTENSION */
diff --git a/components/messaging/ffa/libsp/test/test_mock_sp_rxtx.cpp b/components/messaging/ffa/libsp/mock/test/test_mock_sp_rxtx.cpp
index 66f1f8457..66f1f8457 100644
--- a/components/messaging/ffa/libsp/test/test_mock_sp_rxtx.cpp
+++ b/components/messaging/ffa/libsp/mock/test/test_mock_sp_rxtx.cpp
diff --git a/components/messaging/ffa/libsp/sp_discovery.c b/components/messaging/ffa/libsp/sp_discovery.c
index e78c93d0c..7f92b6bcb 100644
--- a/components/messaging/ffa/libsp/sp_discovery.c
+++ b/components/messaging/ffa/libsp/sp_discovery.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*/
#include "sp_discovery.h"
@@ -38,155 +38,127 @@ sp_result sp_discovery_own_id_get(uint16_t *id)
return SP_RESULT_FFA(ffa_res);
}
+static void unpack_ffa_info(const struct ffa_partition_information *ffa_info,
+ struct sp_partition_info *sp_info)
+{
+ uint32_t props = ffa_info->partition_properties;
+
+ sp_info->partition_id = ffa_info->partition_id;
+ sp_info->execution_context_count = ffa_info->execution_context_count;
+ sp_info->supports_direct_requests =
+ props & FFA_PARTITION_SUPPORTS_DIRECT_REQUESTS;
+ sp_info->can_send_direct_requests =
+ props & FFA_PARTITION_CAN_SEND_DIRECT_REQUESTS;
+ sp_info->supports_indirect_requests =
+ props & FFA_PARTITION_SUPPORTS_INDIRECT_REQUESTS;
+}
+
static sp_result
partition_info_get(const struct sp_uuid *uuid,
- const struct ffa_partition_information **info,
- uint32_t *count)
+ struct sp_partition_info info[],
+ uint32_t *count,
+ bool allow_nil_uuid)
{
+ const struct ffa_partition_information *ffa_info = NULL;
+ uint32_t ffa_count = 0;
+ uint32_t i = 0;
+ sp_result sp_res = SP_RESULT_OK;
const void *buffer = NULL;
size_t buffer_size = 0;
struct ffa_uuid ffa_uuid = { 0 };
- sp_result sp_res = SP_RESULT_OK;
ffa_result ffa_res = FFA_OK;
+ if (count == NULL)
+ return SP_RESULT_INVALID_PARAMETERS;
+
+ if (info == NULL) {
+ *count = UINT32_C(0);
+ return SP_RESULT_INVALID_PARAMETERS;
+ }
+
+ if (uuid == NULL || (!allow_nil_uuid &&
+ memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0)) {
+ sp_res = SP_RESULT_INVALID_PARAMETERS;
+ goto out;
+ }
+
sp_res = sp_rxtx_buffer_rx_get(&buffer, &buffer_size);
if (sp_res != SP_RESULT_OK) {
- *count = UINT32_C(0);
- return sp_res;
+ goto out;
}
/* Safely convert to FF-A UUID format */
memcpy(&ffa_uuid.uuid, uuid->uuid, sizeof(ffa_uuid.uuid));
- ffa_res = ffa_partition_info_get(&ffa_uuid, count);
+ ffa_res = ffa_partition_info_get(&ffa_uuid, &ffa_count);
if (ffa_res != FFA_OK) {
- *count = UINT32_C(0);
- return SP_RESULT_FFA(ffa_res);
+ sp_res = SP_RESULT_FFA(ffa_res);
+ goto out;
}
- if ((*count * sizeof(struct ffa_partition_information)) > buffer_size) {
+ if ((ffa_count * sizeof(struct ffa_partition_information)) > buffer_size) {
/*
* The indicated amount of info structures doesn't fit into the
* RX buffer.
*/
- *count = UINT32_C(0);
- return SP_RESULT_INTERNAL_ERROR;
+ sp_res = SP_RESULT_INTERNAL_ERROR;
+ goto out;
}
- *info = (const struct ffa_partition_information *)buffer;
-
- return SP_RESULT_OK;
-}
-
-static sp_result
-partition_info_get_single(const struct sp_uuid *uuid,
- const struct ffa_partition_information **info)
-{
- uint32_t count = 0;
- sp_result sp_res = SP_RESULT_OK;
-
- if (uuid == NULL)
- return SP_RESULT_INVALID_PARAMETERS;
+ ffa_info = (const struct ffa_partition_information *)buffer;
- /*
- * Nil UUID means querying all partitions which is handled by a separate
- * function.
- */
- if (memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0)
- return SP_RESULT_INVALID_PARAMETERS;
-
- sp_res = partition_info_get(uuid, info, &count);
- if (sp_res != SP_RESULT_OK)
- return sp_res;
+ if (ffa_count == 0) {
+ sp_res = SP_RESULT_NOT_FOUND;
+ goto out;
+ }
- if (count == 0)
- return SP_RESULT_NOT_FOUND;
+ *count = MIN(*count, ffa_count);
+ for (i = 0; i < *count; i++)
+ unpack_ffa_info(&ffa_info[i], &info[i]);
return SP_RESULT_OK;
-}
-static void unpack_ffa_info(const struct ffa_partition_information ffa_info[],
- struct sp_partition_info *sp_info)
-{
- uint32_t props = ffa_info->partition_properties;
+out:
+ for (i = 0; i < *count; i++)
+ info[i] = (struct sp_partition_info){ 0 };
+ *count = UINT32_C(0);
- sp_info->partition_id = ffa_info->partition_id;
- sp_info->execution_context_count = ffa_info->execution_context_count;
- sp_info->supports_direct_requests =
- props & FFA_PARTITION_SUPPORTS_DIRECT_REQUESTS;
- sp_info->can_send_direct_requests =
- props & FFA_PARTITION_CAN_SEND_DIRECT_REQUESTS;
- sp_info->supports_indirect_requests =
- props & FFA_PARTITION_SUPPORTS_INDIRECT_REQUESTS;
+ return sp_res;
}
sp_result sp_discovery_partition_id_get(const struct sp_uuid *uuid,
uint16_t *id)
{
- const struct ffa_partition_information *ffa_info = NULL;
- uint32_t count = 0;
+ struct sp_partition_info sp_info = { 0 };
sp_result sp_res = SP_RESULT_OK;
+ uint32_t count = 1;
if (id == NULL)
return SP_RESULT_INVALID_PARAMETERS;
- sp_res = partition_info_get_single(uuid, &ffa_info);
- if (sp_res != SP_RESULT_OK) {
- *id = FFA_ID_GET_ID_MASK;
+ *id = FFA_ID_GET_ID_MASK;
+
+ if (uuid == NULL || memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0)
+ return SP_RESULT_INVALID_PARAMETERS;
+
+ sp_res = partition_info_get(uuid, &sp_info, &count, false);
+ if (sp_res != SP_RESULT_OK)
return sp_res;
- }
- *id = ffa_info->partition_id;
+ *id = sp_info.partition_id;
return SP_RESULT_OK;
}
sp_result sp_discovery_partition_info_get(const struct sp_uuid *uuid,
- struct sp_partition_info *info)
+ struct sp_partition_info info[],
+ uint32_t *count)
{
- const struct ffa_partition_information *ffa_info = NULL;
- uint32_t count = 0;
- sp_result sp_res = SP_RESULT_OK;
-
- if (info == NULL)
- return SP_RESULT_INVALID_PARAMETERS;
-
- sp_res = partition_info_get_single(uuid, &ffa_info);
- if (sp_res != SP_RESULT_OK) {
- *info = (struct sp_partition_info){ 0 };
- return sp_res;
- }
-
- unpack_ffa_info(ffa_info, info);
-
- return SP_RESULT_OK;
+ return partition_info_get(uuid, info, count, false);
}
sp_result sp_discovery_partition_info_get_all(struct sp_partition_info info[],
uint32_t *count)
{
- const struct ffa_partition_information *ffa_info = NULL;
- uint32_t ffa_count = 0;
- uint32_t i = 0;
- sp_result sp_res = SP_RESULT_OK;
-
- if (count == NULL)
- return SP_RESULT_INVALID_PARAMETERS;
-
- if (info == NULL) {
- *count = UINT32_C(0);
- return SP_RESULT_INVALID_PARAMETERS;
- }
-
- sp_res = partition_info_get(&uuid_nil, &ffa_info, &ffa_count);
- if (sp_res != SP_RESULT_OK) {
- *count = UINT32_C(0);
- return sp_res;
- }
-
- *count = MIN(*count, ffa_count);
- for (i = 0; i < *count; i++)
- unpack_ffa_info(&ffa_info[i], &info[i]);
-
- return SP_RESULT_OK;
+ return partition_info_get(&uuid_nil, info, count, true);
}
diff --git a/components/messaging/ffa/libsp/sp_memory_management.c b/components/messaging/ffa/libsp/sp_memory_management.c
index 52d03ac16..3dbeb61df 100644
--- a/components/messaging/ffa/libsp/sp_memory_management.c
+++ b/components/messaging/ffa/libsp/sp_memory_management.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*/
#include "sp_memory_management.h"
@@ -560,14 +560,23 @@ sp_result sp_memory_retrieve(struct sp_memory_descriptor *descriptor,
/* Fragmentation is not supported currently */
if (resp_total_length != resp_fragment_length) {
*out_region_count = UINT32_C(0);
- return SP_RESULT_INTERNAL_ERROR;
+ sp_res = SP_RESULT_INTERNAL_ERROR;
+ goto out;
}
rx_buffer.used = resp_total_length;
parse_descriptors(&rx_buffer, descriptor, acc_desc, 1, regions,
out_region_count);
- return SP_RESULT_OK;
+out:
+ ffa_res = ffa_rx_release();
+ if (ffa_res != FFA_OK) {
+ /* Keep original error when there was already an error.*/
+ if (sp_res == SP_RESULT_OK)
+ return SP_RESULT_FFA(ffa_res);
+ }
+
+ return sp_res;
}
sp_result
@@ -664,3 +673,102 @@ sp_result sp_memory_reclaim(uint64_t handle, uint32_t flags)
{
return SP_RESULT_FFA(ffa_mem_reclaim(handle, flags));
}
+
+sp_result sp_memory_permission_get(const void *base_address,
+ struct sp_mem_perm *mem_perm)
+{
+ ffa_result result = FFA_OK;
+ uint32_t raw_mem_perm = 0;
+
+ /* Checking for invalid parameters*/
+ if (!base_address || !mem_perm)
+ return SP_RESULT_INVALID_PARAMETERS;
+
+ /* Checking address alignment */
+ if (((uintptr_t)base_address & FFA_MEM_PERM_PAGE_MASK) != 0)
+ return SP_RESULT_INVALID_PARAMETERS;
+
+ /* Mapping the buffers */
+ result = ffa_mem_perm_get(base_address, &raw_mem_perm);
+ if (result != FFA_OK)
+ return SP_RESULT_FFA(result);
+
+ /* Parsing permissions */
+ switch (raw_mem_perm & FFA_MEM_PERM_DATA_ACCESS_PERM_MASK) {
+ case FFA_MEM_PERM_DATA_ACCESS_PERM_NO_ACCESS:
+ mem_perm->data_access = sp_mem_perm_data_perm_no_access;
+ break;
+ case FFA_MEM_PERM_DATA_ACCESS_PERM_RW:
+ mem_perm->data_access = sp_mem_perm_data_perm_read_write;
+ break;
+ case FFA_MEM_PERM_DATA_ACCESS_PERM_RO:
+ mem_perm->data_access = sp_mem_perm_data_perm_read_only;
+ break;
+ default:
+ return SP_RESULT_INTERNAL_ERROR;
+ }
+
+ if ((raw_mem_perm & FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_MASK) ==
+ FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_X)
+ mem_perm->instruction_access = sp_mem_perm_instruction_perm_executable;
+ else
+ mem_perm->instruction_access = sp_mem_perm_instruction_perm_non_executable;
+
+ return SP_RESULT_OK;
+}
+
+sp_result sp_memory_permission_set(const void *base_address, size_t region_size,
+ const struct sp_mem_perm *mem_perm)
+{
+ uint32_t raw_mem_perm = 0;
+
+ /* Checking for invalid parameters*/
+ if (!base_address || !region_size || !mem_perm)
+ return SP_RESULT_INVALID_PARAMETERS;
+
+ /* RW and X permissions is prohibited */
+ if (mem_perm->data_access == sp_mem_perm_data_perm_read_write &&
+ mem_perm->instruction_access == sp_mem_perm_instruction_perm_executable)
+ return SP_RESULT_INVALID_PARAMETERS;
+
+ switch (mem_perm->data_access) {
+ case sp_mem_perm_data_perm_no_access:
+ raw_mem_perm |= FFA_MEM_PERM_DATA_ACCESS_PERM_NO_ACCESS <<
+ FFA_MEM_ACCESS_PERM_DATA_SHIFT;
+ break;
+ case sp_mem_perm_data_perm_read_write:
+ raw_mem_perm |= FFA_MEM_PERM_DATA_ACCESS_PERM_RW <<
+ FFA_MEM_ACCESS_PERM_DATA_SHIFT;
+ break;
+ case sp_mem_perm_data_perm_read_only:
+ raw_mem_perm |= FFA_MEM_PERM_DATA_ACCESS_PERM_RO <<
+ FFA_MEM_ACCESS_PERM_DATA_SHIFT;
+ break;
+ default:
+ return SP_RESULT_INVALID_PARAMETERS;
+ }
+
+ switch (mem_perm->instruction_access) {
+ case sp_mem_perm_instruction_perm_executable:
+ raw_mem_perm |= FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_X;
+ break;
+ case sp_mem_perm_instruction_perm_non_executable:
+ raw_mem_perm |= FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_NX;
+ break;
+ default:
+ return SP_RESULT_INVALID_PARAMETERS;
+ }
+
+ /* Checking address alignment */
+ if (((uintptr_t)base_address & FFA_MEM_PERM_PAGE_MASK) != 0 ||
+ (region_size & FFA_MEM_PERM_PAGE_MASK) != 0)
+ return SP_RESULT_INVALID_PARAMETERS;
+
+ /* Calculating page count */
+ region_size /= FFA_MEM_PERM_PAGE_SIZE;
+ if (region_size > FFA_MEM_PERM_PAGE_COUNT_MAX)
+ return SP_RESULT_INVALID_PARAMETERS;
+
+ /* Changing memory permissions */
+ return SP_RESULT_FFA(ffa_mem_perm_set(base_address, region_size, raw_mem_perm));
+}
diff --git a/components/messaging/ffa/libsp/sp_messaging.c b/components/messaging/ffa/libsp/sp_messaging.c
index ba07ce158..67fd7ee88 100644
--- a/components/messaging/ffa/libsp/sp_messaging.c
+++ b/components/messaging/ffa/libsp/sp_messaging.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#include "ffa_api.h"
@@ -12,34 +12,43 @@
#include <string.h>
-#define SP_MSG_ARG_OFFSET (1)
-
static void pack_ffa_direct_msg(const struct sp_msg *msg,
struct ffa_direct_msg *ffa_msg)
{
- uint32_t i = 0;
-
ffa_msg->source_id = msg->source_id;
ffa_msg->destination_id = msg->destination_id;
- ffa_msg->args[0] = 0;
- memcpy(&ffa_msg->args[SP_MSG_ARG_OFFSET], msg->args, sizeof(msg->args));
+ if (msg->is_64bit_message) {
+ ffa_msg->function_id = FFA_TO_64_BIT_FUNC(0);
+ memcpy(ffa_msg->args.args64, msg->args.args64, sizeof(msg->args.args64));
+ } else {
+ memcpy(ffa_msg->args.args32, msg->args.args32, sizeof(msg->args.args32));
+ }
}
static void unpack_ffa_direct_msg(const struct ffa_direct_msg *ffa_msg,
struct sp_msg *msg)
{
- uint32_t i = 0;
+ if (ffa_msg->function_id == FFA_MSG_SEND_DIRECT_REQ_32 ||
+ ffa_msg->function_id == FFA_MSG_SEND_DIRECT_RESP_32) {
+ /*
+ * Handling 32 bit request or response
+ */
+ msg->source_id = ffa_msg->source_id;
+ msg->destination_id = ffa_msg->destination_id;
+ msg->is_64bit_message = false;
- if (ffa_msg->function_id != FFA_SUCCESS_32) {
+ memcpy(msg->args.args32, ffa_msg->args.args32, sizeof(msg->args.args32));
+ } else if (ffa_msg->function_id == FFA_MSG_SEND_DIRECT_REQ_64 ||
+ ffa_msg->function_id == FFA_MSG_SEND_DIRECT_RESP_64) {
/*
- * Handling request or response (error is handled before call)
+ * Handling 64 bit request or response
*/
msg->source_id = ffa_msg->source_id;
msg->destination_id = ffa_msg->destination_id;
+ msg->is_64bit_message = true;
- memcpy(msg->args, &ffa_msg->args[SP_MSG_ARG_OFFSET],
- sizeof(msg->args));
+ memcpy(msg->args.args64, ffa_msg->args.args64, sizeof(msg->args.args64));
} else {
/* Success has no message parameters */
*msg = (struct sp_msg){ 0 };
@@ -90,14 +99,25 @@ sp_result sp_msg_send_direct_req(const struct sp_msg *req, struct sp_msg *resp)
pack_ffa_direct_msg(req, &ffa_req);
#if FFA_DIRECT_MSG_ROUTING_EXTENSION
- ffa_direct_msg_routing_ext_req_pre_hook(&ffa_req);
+ ffa_res = ffa_direct_msg_routing_ext_req_pre_hook(&ffa_req);
+ if (ffa_res != FFA_OK) {
+ *resp = (struct sp_msg){ 0 };
+ return SP_RESULT_INVALID_PARAMETERS;
+ }
#endif
- ffa_res = ffa_msg_send_direct_req(ffa_req.source_id,
- ffa_req.destination_id,
- ffa_req.args[0], ffa_req.args[1],
- ffa_req.args[2], ffa_req.args[3],
- ffa_req.args[4], &ffa_resp);
+ if (req->is_64bit_message)
+ ffa_res = ffa_msg_send_direct_req_64(
+ ffa_req.source_id, ffa_req.destination_id,
+ ffa_req.args.args64[0], ffa_req.args.args64[1],
+ ffa_req.args.args64[2], ffa_req.args.args64[3],
+ ffa_req.args.args64[4], &ffa_resp);
+ else
+ ffa_res = ffa_msg_send_direct_req_32(
+ ffa_req.source_id, ffa_req.destination_id,
+ ffa_req.args.args32[0], ffa_req.args.args32[1],
+ ffa_req.args.args32[2], ffa_req.args.args32[3],
+ ffa_req.args.args32[4], &ffa_resp);
if (ffa_res != FFA_OK) {
#if FFA_DIRECT_MSG_ROUTING_EXTENSION
@@ -137,14 +157,25 @@ sp_result sp_msg_send_direct_resp(const struct sp_msg *resp, struct sp_msg *req)
pack_ffa_direct_msg(resp, &ffa_resp);
#if FFA_DIRECT_MSG_ROUTING_EXTENSION
- ffa_direct_msg_routing_ext_resp_pre_hook(&ffa_resp);
+ ffa_res = ffa_direct_msg_routing_ext_resp_pre_hook(&ffa_resp);
+ if (ffa_res != FFA_OK) {
+ *req = (struct sp_msg){ 0 };
+ return SP_RESULT_INVALID_PARAMETERS;
+ }
#endif
- ffa_res = ffa_msg_send_direct_resp(ffa_resp.source_id,
- ffa_resp.destination_id,
- ffa_resp.args[0], ffa_resp.args[1],
- ffa_resp.args[2], ffa_resp.args[3],
- ffa_resp.args[4], &ffa_req);
+ if (resp->is_64bit_message)
+ ffa_res = ffa_msg_send_direct_resp_64(
+ ffa_resp.source_id, ffa_resp.destination_id,
+ ffa_resp.args.args64[0], ffa_resp.args.args64[1],
+ ffa_resp.args.args64[2], ffa_resp.args.args64[3],
+ ffa_resp.args.args64[4], &ffa_req);
+ else
+ ffa_res = ffa_msg_send_direct_resp_32(
+ ffa_resp.source_id, ffa_resp.destination_id,
+ ffa_resp.args.args32[0], ffa_resp.args.args32[1],
+ ffa_resp.args.args32[2], ffa_resp.args.args32[3],
+ ffa_resp.args.args32[4], &ffa_req);
if (ffa_res != FFA_OK) {
#if FFA_DIRECT_MSG_ROUTING_EXTENSION
@@ -184,13 +215,17 @@ sp_result sp_msg_send_rc_req(const struct sp_msg *req, struct sp_msg *resp)
pack_ffa_direct_msg(req, &ffa_req);
- ffa_direct_msg_routing_ext_rc_req_pre_hook(&ffa_req);
+ ffa_res = ffa_direct_msg_routing_ext_rc_req_pre_hook(&ffa_req);
+ if (ffa_res != FFA_OK) {
+ *resp = (struct sp_msg){ 0 };
+ return SP_RESULT_INVALID_PARAMETERS;
+ }
- ffa_res = ffa_msg_send_direct_resp(ffa_req.source_id,
+ ffa_res = ffa_msg_send_direct_resp_32(ffa_req.source_id,
ffa_req.destination_id,
- ffa_req.args[0], ffa_req.args[1],
- ffa_req.args[2], ffa_req.args[3],
- ffa_req.args[4], &ffa_resp);
+ ffa_req.args.args32[0], ffa_req.args.args32[1],
+ ffa_req.args.args32[2], ffa_req.args.args32[3],
+ ffa_req.args.args32[4], &ffa_resp);
if (ffa_res != FFA_OK) {
ffa_direct_msg_routing_ext_rc_req_error_hook();
diff --git a/components/messaging/ffa/libsp/sp_rxtx.c b/components/messaging/ffa/libsp/sp_rxtx.c
index fb88f73b8..317ececd6 100644
--- a/components/messaging/ffa/libsp/sp_rxtx.c
+++ b/components/messaging/ffa/libsp/sp_rxtx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*/
#include "sp_rxtx.h"
@@ -99,7 +99,7 @@ sp_result sp_rxtx_buffer_alignment_boundary_get(uintptr_t *alignment)
return SP_RESULT_INVALID_PARAMETERS;
/* Querying FFX_RXTX_MAP features */
- result = ffa_features(FFA_RXTX_MAP_32, &interface_props);
+ result = ffa_features(FFA_RXTX_MAP_64, &interface_props);
if (result != FFA_OK) {
*alignment = 0;
return SP_RESULT_FFA(result);
diff --git a/components/messaging/ffa/libsp/test/test_ffa_api.cpp b/components/messaging/ffa/libsp/test/test_ffa_api.cpp
index 5ab7c8a5d..8395662bf 100644
--- a/components/messaging/ffa/libsp/test/test_ffa_api.cpp
+++ b/components/messaging/ffa/libsp/test/test_ffa_api.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*/
#include <CppUTest/TestHarness.h>
@@ -43,20 +43,35 @@ TEST_GROUP(ffa_api)
svc_result.a2 = (uint32_t)error_code;
}
- void msg_equal(uint32_t func_id, uint16_t source_id, uint16_t dest_id,
- uint32_t arg0, uint32_t arg1, uint32_t arg2,
- uint32_t arg3, uint32_t arg4)
+ void msg_equal_32(uint32_t func_id, uint16_t source_id, uint16_t dest_id,
+ uint32_t arg0, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4)
{
UNSIGNED_LONGS_EQUAL(func_id, msg.function_id);
UNSIGNED_LONGS_EQUAL(source_id, msg.source_id);
UNSIGNED_LONGS_EQUAL(dest_id, msg.destination_id);
- UNSIGNED_LONGS_EQUAL(arg0, msg.args[0]);
- UNSIGNED_LONGS_EQUAL(arg1, msg.args[1]);
- UNSIGNED_LONGS_EQUAL(arg2, msg.args[2]);
- UNSIGNED_LONGS_EQUAL(arg3, msg.args[3]);
- UNSIGNED_LONGS_EQUAL(arg4, msg.args[4]);
+ UNSIGNED_LONGS_EQUAL(arg0, msg.args.args32[0]);
+ UNSIGNED_LONGS_EQUAL(arg1, msg.args.args32[1]);
+ UNSIGNED_LONGS_EQUAL(arg2, msg.args.args32[2]);
+ UNSIGNED_LONGS_EQUAL(arg3, msg.args.args32[3]);
+ UNSIGNED_LONGS_EQUAL(arg4, msg.args.args32[4]);
}
+ void msg_equal_64(uint32_t func_id, uint16_t source_id, uint16_t dest_id,
+ uint64_t arg0, uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4)
+ {
+ UNSIGNED_LONGS_EQUAL(func_id, msg.function_id);
+ UNSIGNED_LONGS_EQUAL(source_id, msg.source_id);
+ UNSIGNED_LONGS_EQUAL(dest_id, msg.destination_id);
+ UNSIGNED_LONGLONGS_EQUAL(arg0, msg.args.args64[0]);
+ UNSIGNED_LONGLONGS_EQUAL(arg1, msg.args.args64[1]);
+ UNSIGNED_LONGLONGS_EQUAL(arg2, msg.args.args64[2]);
+ UNSIGNED_LONGLONGS_EQUAL(arg3, msg.args.args64[3]);
+ UNSIGNED_LONGLONGS_EQUAL(arg4, msg.args.args64[4]);
+ }
+
+
struct ffa_params svc_result;
struct ffa_direct_msg msg;
};
@@ -169,7 +184,7 @@ TEST(ffa_api, ffa_rxtx_map)
const uint64_t page_count = (1 << 6) - 1;
svc_result.a0 = 0x84000061;
- expect_ffa_svc(0x84000066, tx_buffer, rx_buffer, page_count, 0, 0, 0, 0,
+ expect_ffa_svc(0xc4000066, tx_buffer, rx_buffer, page_count, 0, 0, 0, 0,
&svc_result);
ffa_result result = ffa_rxtx_map((const void *)tx_buffer,
@@ -184,7 +199,7 @@ TEST(ffa_api, ffa_rxtx_map_error)
const uint64_t page_count = (1 << 6) - 1;
setup_error_response(-1);
- expect_ffa_svc(0x84000066, tx_buffer, rx_buffer, page_count, 0, 0, 0, 0,
+ expect_ffa_svc(0xc4000066, tx_buffer, rx_buffer, page_count, 0, 0, 0, 0,
&svc_result);
ffa_result result = ffa_rxtx_map((const void *)tx_buffer,
@@ -200,7 +215,7 @@ TEST(ffa_api, ffa_rxtx_map_unknown_response)
assert_environment_t assert_env;
svc_result.a0 = 0x12345678;
- expect_ffa_svc(0x84000066, tx_buffer, rx_buffer, page_count, 0, 0, 0, 0,
+ expect_ffa_svc(0xc4000066, tx_buffer, rx_buffer, page_count, 0, 0, 0, 0,
&svc_result);
if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
@@ -360,7 +375,7 @@ TEST(ffa_api, ffa_msg_wait_success)
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
ffa_result result = ffa_msg_wait(&msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
TEST(ffa_api, ffa_msg_wait_error)
@@ -369,10 +384,10 @@ TEST(ffa_api, ffa_msg_wait_error)
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
ffa_result result = ffa_msg_wait(&msg);
LONGS_EQUAL(-1, result);
- msg_equal(0, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_wait_direct_req)
+TEST(ffa_api, ffa_msg_wait_direct_req_32)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -392,7 +407,31 @@ TEST(ffa_api, ffa_msg_wait_direct_req)
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
ffa_result result = ffa_msg_wait(&msg);
LONGS_EQUAL(0, result);
- msg_equal(0x8400006F, source_id, dest_id, arg0, arg1, arg2, arg3,
+ msg_equal_32(0x8400006F, source_id, dest_id, arg0, arg1, arg2, arg3,
+ arg4);
+}
+
+TEST(ffa_api, ffa_msg_wait_direct_req_64)
+{
+ const uint16_t source_id = 0x1122;
+ const uint16_t dest_id = 0x3344;
+ const uint64_t arg0 = 0x0123456776543210ULL;
+ const uint64_t arg1 = 0x1234567887654321ULL;
+ const uint64_t arg2 = 0x2345678998765432ULL;
+ const uint64_t arg3 = 0x3456789aa9876543ULL;
+ const uint64_t arg4 = 0x456789abba987654ULL;
+
+ svc_result.a0 = 0xC400006F;
+ svc_result.a1 = ((uint32_t)source_id) << 16 | dest_id;
+ svc_result.a3 = arg0;
+ svc_result.a4 = arg1;
+ svc_result.a5 = arg2;
+ svc_result.a6 = arg3;
+ svc_result.a7 = arg4;
+ expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
+ ffa_result result = ffa_msg_wait(&msg);
+ LONGS_EQUAL(0, result);
+ msg_equal_64(0xC400006F, source_id, dest_id, arg0, arg1, arg2, arg3,
arg4);
}
@@ -410,7 +449,7 @@ TEST(ffa_api, ffa_msg_wait_one_interrupt_success)
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
ffa_result result = ffa_msg_wait(&msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
TEST(ffa_api, ffa_msg_wait_two_interrupt_success)
@@ -434,7 +473,7 @@ TEST(ffa_api, ffa_msg_wait_two_interrupt_success)
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
ffa_result result = ffa_msg_wait(&msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
TEST(ffa_api, ffa_msg_wait_unknown_response)
@@ -448,7 +487,7 @@ TEST(ffa_api, ffa_msg_wait_unknown_response)
}
}
-TEST(ffa_api, ffa_msg_send_direct_req_success)
+TEST(ffa_api, ffa_msg_send_direct_req_32_success)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -461,13 +500,13 @@ TEST(ffa_api, ffa_msg_send_direct_req_success)
svc_result.a0 = 0x84000061;
expect_ffa_svc(0x8400006F, ((uint32_t)source_id << 16) | dest_id, 0,
arg0, arg1, arg2, arg3, arg4, &svc_result);
- ffa_result result = ffa_msg_send_direct_req(
+ ffa_result result = ffa_msg_send_direct_req_32(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_send_direct_req_error)
+TEST(ffa_api, ffa_msg_send_direct_req_32_error)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -480,13 +519,48 @@ TEST(ffa_api, ffa_msg_send_direct_req_error)
setup_error_response(-1);
expect_ffa_svc(0x8400006F, ((uint32_t)source_id << 16) | dest_id, 0,
arg0, arg1, arg2, arg3, arg4, &svc_result);
- ffa_result result = ffa_msg_send_direct_req(
+ ffa_result result = ffa_msg_send_direct_req_32(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(-1, result);
- msg_equal(0, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_send_direct_req_direct_resp)
+TEST(ffa_api, ffa_msg_send_direct_req_32_get_resp_64)
+{
+ const uint16_t source_id = 0x1122;
+ const uint16_t dest_id = 0x3344;
+ const uint32_t arg0 = 0x01234567ULL;
+ const uint32_t arg1 = 0x12345678ULL;
+ const uint32_t arg2 = 0x23456789ULL;
+ const uint32_t arg3 = 0x3456789aULL;
+ const uint32_t arg4 = 0x456789abULL;
+ const uint16_t resp_source_id = 0x1221;
+ const uint16_t resp_dest_id = 0x3443;
+ const uint64_t resp_arg0 = 0x9012345665432109ULL;
+ const uint64_t resp_arg1 = 0xa12345677654321aULL;
+ const uint64_t resp_arg2 = 0xb23456788765432bULL;
+ const uint64_t resp_arg3 = 0xc34567899876543cULL;
+ const uint64_t resp_arg4 = 0xd456789aa987654dULL;
+ assert_environment_t assert_env;
+
+ svc_result.a0 = 0xC4000070;
+ svc_result.a1 = ((uint32_t)resp_source_id) << 16 | resp_dest_id;
+ svc_result.a3 = resp_arg0;
+ svc_result.a4 = resp_arg1;
+ svc_result.a5 = resp_arg2;
+ svc_result.a6 = resp_arg3;
+ svc_result.a7 = resp_arg4;
+
+ expect_ffa_svc(0x8400006F, ((uint32_t)source_id << 16) | dest_id, 0,
+ arg0, arg1, arg2, arg3, arg4, &svc_result);
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_msg_send_direct_req_32(source_id, dest_id, arg0, arg1, arg2,
+ arg3, arg4, &msg);
+ }
+}
+
+TEST(ffa_api, ffa_msg_send_direct_req_32_direct_resp)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -512,14 +586,82 @@ TEST(ffa_api, ffa_msg_send_direct_req_direct_resp)
svc_result.a7 = resp_arg4;
expect_ffa_svc(0x8400006F, ((uint32_t)source_id << 16) | dest_id, 0,
arg0, arg1, arg2, arg3, arg4, &svc_result);
- ffa_result result = ffa_msg_send_direct_req(
+ ffa_result result = ffa_msg_send_direct_req_32(
+ source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
+ LONGS_EQUAL(0, result);
+ msg_equal_32(0x84000070, resp_source_id, resp_dest_id, resp_arg0,
+ resp_arg1, resp_arg2, resp_arg3, resp_arg4);
+}
+
+TEST(ffa_api, ffa_msg_send_direct_req_64_success)
+{
+ const uint16_t source_id = 0x1122;
+ const uint16_t dest_id = 0x3344;
+ const uint64_t arg0 = 0x0123456776543210ULL;
+ const uint64_t arg1 = 0x1234567887654321ULL;
+ const uint64_t arg2 = 0x2345678998765432ULL;
+ const uint64_t arg3 = 0x3456789aa9876543ULL;
+ const uint64_t arg4 = 0x456789abba987654ULL;
+ const uint16_t resp_source_id = 0x1221;
+ const uint16_t resp_dest_id = 0x3443;
+ const uint64_t resp_arg0 = 0x9012345665432109ULL;
+ const uint64_t resp_arg1 = 0xa12345677654321aULL;
+ const uint64_t resp_arg2 = 0xb23456788765432bULL;
+ const uint64_t resp_arg3 = 0xc34567899876543cULL;
+ const uint64_t resp_arg4 = 0xd456789aa987654dULL;
+
+ svc_result.a0 = 0xC4000070;
+ svc_result.a1 = ((uint32_t)resp_source_id) << 16 | resp_dest_id;
+ svc_result.a3 = resp_arg0;
+ svc_result.a4 = resp_arg1;
+ svc_result.a5 = resp_arg2;
+ svc_result.a6 = resp_arg3;
+ svc_result.a7 = resp_arg4;
+ expect_ffa_svc(0xC400006F, ((uint32_t)source_id << 16) | dest_id, 0,
+ arg0, arg1, arg2, arg3, arg4, &svc_result);
+ ffa_result result = ffa_msg_send_direct_req_64(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000070, resp_source_id, resp_dest_id, resp_arg0,
+ msg_equal_64(0xC4000070, resp_source_id, resp_dest_id, resp_arg0,
resp_arg1, resp_arg2, resp_arg3, resp_arg4);
}
-TEST(ffa_api, ffa_msg_send_direct_req_one_interrupt_success)
+TEST(ffa_api, ffa_msg_send_direct_req_64_get_resp_32)
+{
+ const uint16_t source_id = 0x1122;
+ const uint16_t dest_id = 0x3344;
+ const uint64_t arg0 = 0x9012345665432109ULL;
+ const uint64_t arg1 = 0xa12345677654321aULL;
+ const uint64_t arg2 = 0xb23456788765432bULL;
+ const uint64_t arg3 = 0xc34567899876543cULL;
+ const uint64_t arg4 = 0xd456789aa987654dULL;
+ const uint16_t resp_source_id = 0x1221;
+ const uint16_t resp_dest_id = 0x3443;
+ const uint32_t resp_arg0 = 0x01234567ULL;
+ const uint32_t resp_arg1 = 0x12345678ULL;
+ const uint32_t resp_arg2 = 0x23456789ULL;
+ const uint32_t resp_arg3 = 0x3456789aULL;
+ const uint32_t resp_arg4 = 0x456789abULL;
+ assert_environment_t assert_env;
+
+ svc_result.a0 = 0x84000070;
+ svc_result.a1 = ((uint32_t)resp_source_id) << 16 | resp_dest_id;
+ svc_result.a3 = resp_arg0;
+ svc_result.a4 = resp_arg1;
+ svc_result.a5 = resp_arg2;
+ svc_result.a6 = resp_arg3;
+ svc_result.a7 = resp_arg4;
+
+ expect_ffa_svc(0xC400006F, ((uint32_t)source_id << 16) | dest_id, 0,
+ arg0, arg1, arg2, arg3, arg4, &svc_result);
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_msg_send_direct_req_64(source_id, dest_id, arg0, arg1, arg2,
+ arg3, arg4, &msg);
+ }
+}
+
+TEST(ffa_api, ffa_msg_send_direct_req_32_one_interrupt_success)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -539,13 +681,13 @@ TEST(ffa_api, ffa_msg_send_direct_req_one_interrupt_success)
svc_result.a0 = 0x84000061;
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
- ffa_result result = ffa_msg_send_direct_req(
+ ffa_result result = ffa_msg_send_direct_req_32(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_send_direct_req_two_interrupt_success)
+TEST(ffa_api, ffa_msg_send_direct_req_32_two_interrupt_success)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -573,13 +715,13 @@ TEST(ffa_api, ffa_msg_send_direct_req_two_interrupt_success)
svc_result.a0 = 0x84000061;
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
- ffa_result result = ffa_msg_send_direct_req(
+ ffa_result result = ffa_msg_send_direct_req_32(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_send_direct_req_unknown_response)
+TEST(ffa_api, ffa_msg_send_direct_req_32_unknown_response)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -594,12 +736,12 @@ TEST(ffa_api, ffa_msg_send_direct_req_unknown_response)
expect_ffa_svc(0x8400006F, ((uint32_t)source_id << 16) | dest_id, 0,
arg0, arg1, arg2, arg3, arg4, &svc_result);
if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
- ffa_msg_send_direct_req(source_id, dest_id, arg0, arg1, arg2,
+ ffa_msg_send_direct_req_32(source_id, dest_id, arg0, arg1, arg2,
arg3, arg4, &msg);
}
}
-TEST(ffa_api, ffa_msg_send_direct_resp_success)
+TEST(ffa_api, ffa_msg_send_direct_resp_32_success)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -612,13 +754,13 @@ TEST(ffa_api, ffa_msg_send_direct_resp_success)
svc_result.a0 = 0x84000061;
expect_ffa_svc(0x84000070, ((uint32_t)source_id << 16) | dest_id, 0,
arg0, arg1, arg2, arg3, arg4, &svc_result);
- ffa_result result = ffa_msg_send_direct_resp(
+ ffa_result result = ffa_msg_send_direct_resp_32(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_send_direct_resp_error)
+TEST(ffa_api, ffa_msg_send_direct_resp_32_error)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -631,13 +773,13 @@ TEST(ffa_api, ffa_msg_send_direct_resp_error)
setup_error_response(-1);
expect_ffa_svc(0x84000070, ((uint32_t)source_id << 16) | dest_id, 0,
arg0, arg1, arg2, arg3, arg4, &svc_result);
- ffa_result result = ffa_msg_send_direct_resp(
+ ffa_result result = ffa_msg_send_direct_resp_32(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(-1, result);
- msg_equal(0, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_send_direct_resp_then_get_direct_req_as_response)
+TEST(ffa_api, ffa_msg_send_direct_resp_32_then_get_direct_req_32_as_response)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -663,14 +805,113 @@ TEST(ffa_api, ffa_msg_send_direct_resp_then_get_direct_req_as_response)
svc_result.a7 = resp_arg4;
expect_ffa_svc(0x84000070, ((uint32_t)source_id << 16) | dest_id, 0,
arg0, arg1, arg2, arg3, arg4, &svc_result);
- ffa_result result = ffa_msg_send_direct_resp(
+ ffa_result result = ffa_msg_send_direct_resp_32(
+ source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
+ LONGS_EQUAL(0, result);
+ msg_equal_32(0x8400006F, resp_source_id, resp_dest_id, resp_arg0,
+ resp_arg1, resp_arg2, resp_arg3, resp_arg4);
+}
+
+TEST(ffa_api, ffa_msg_send_direct_resp_32_then_get_direct_req_64_as_response)
+{
+ const uint16_t source_id = 0x1122;
+ const uint16_t dest_id = 0x3344;
+ const uint32_t arg0 = 0x01234567ULL;
+ const uint32_t arg1 = 0x12345678ULL;
+ const uint32_t arg2 = 0x23456789ULL;
+ const uint32_t arg3 = 0x3456789aULL;
+ const uint32_t arg4 = 0x456789abULL;
+ const uint16_t resp_source_id = 0x1221;
+ const uint16_t resp_dest_id = 0x3443;
+ const uint64_t resp_arg0 = 0x9012345665432109ULL;
+ const uint64_t resp_arg1 = 0xa12345677654321aULL;
+ const uint64_t resp_arg2 = 0xb23456788765432bULL;
+ const uint64_t resp_arg3 = 0xc34567899876543cULL;
+ const uint64_t resp_arg4 = 0xd456789aa987654dULL;
+
+ svc_result.a0 = 0xC400006F;
+ svc_result.a1 = ((uint32_t)resp_source_id) << 16 | resp_dest_id;
+ svc_result.a3 = resp_arg0;
+ svc_result.a4 = resp_arg1;
+ svc_result.a5 = resp_arg2;
+ svc_result.a6 = resp_arg3;
+ svc_result.a7 = resp_arg4;
+ expect_ffa_svc(0x84000070, ((uint32_t)source_id << 16) | dest_id, 0,
+ arg0, arg1, arg2, arg3, arg4, &svc_result);
+ ffa_result result = ffa_msg_send_direct_resp_32(
+ source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
+ LONGS_EQUAL(0, result);
+ msg_equal_64(0xC400006F, resp_source_id, resp_dest_id, resp_arg0,
+ resp_arg1, resp_arg2, resp_arg3, resp_arg4);
+}
+
+TEST(ffa_api, ffa_msg_send_direct_resp_64_then_get_direct_req_32_as_response)
+{
+ const uint16_t source_id = 0x1122;
+ const uint16_t dest_id = 0x3344;
+ const uint64_t arg0 = 0x9012345665432109ULL;
+ const uint64_t arg1 = 0xa12345677654321aULL;
+ const uint64_t arg2 = 0xb23456788765432bULL;
+ const uint64_t arg3 = 0xc34567899876543cULL;
+ const uint64_t arg4 = 0xd456789aa987654dULL;
+ const uint16_t resp_source_id = 0x1221;
+ const uint16_t resp_dest_id = 0x3443;
+ const uint32_t resp_arg0 = 0x01234567ULL;
+ const uint32_t resp_arg1 = 0x12345678ULL;
+ const uint32_t resp_arg2 = 0x23456789ULL;
+ const uint32_t resp_arg3 = 0x3456789aULL;
+ const uint32_t resp_arg4 = 0x456789abULL;
+
+ svc_result.a0 = 0x8400006F;
+ svc_result.a1 = ((uint32_t)resp_source_id) << 16 | resp_dest_id;
+ svc_result.a3 = resp_arg0;
+ svc_result.a4 = resp_arg1;
+ svc_result.a5 = resp_arg2;
+ svc_result.a6 = resp_arg3;
+ svc_result.a7 = resp_arg4;
+ expect_ffa_svc(0xC4000070, ((uint32_t)source_id << 16) | dest_id, 0,
+ arg0, arg1, arg2, arg3, arg4, &svc_result);
+ ffa_result result = ffa_msg_send_direct_resp_64(
+ source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
+ LONGS_EQUAL(0, result);
+ msg_equal_32(0x8400006F, resp_source_id, resp_dest_id, resp_arg0,
+ resp_arg1, resp_arg2, resp_arg3, resp_arg4);
+}
+
+TEST(ffa_api, ffa_msg_send_direct_resp_64_then_get_direct_req_64_as_response)
+{
+ const uint16_t source_id = 0x1122;
+ const uint16_t dest_id = 0x3344;
+ const uint64_t arg0 = 0x0123456776543210ULL;
+ const uint64_t arg1 = 0x1234567887654321ULL;
+ const uint64_t arg2 = 0x2345678998765432ULL;
+ const uint64_t arg3 = 0x3456789aa9876543ULL;
+ const uint64_t arg4 = 0x456789abba987654ULL;
+ const uint16_t resp_source_id = 0x1221;
+ const uint16_t resp_dest_id = 0x3443;
+ const uint64_t resp_arg0 = 0x9012345665432109ULL;
+ const uint64_t resp_arg1 = 0xa12345677654321aULL;
+ const uint64_t resp_arg2 = 0xb23456788765432bULL;
+ const uint64_t resp_arg3 = 0xc34567899876543cULL;
+ const uint64_t resp_arg4 = 0xd456789aa987654dULL;
+
+ svc_result.a0 = 0xC400006F;
+ svc_result.a1 = ((uint32_t)resp_source_id) << 16 | resp_dest_id;
+ svc_result.a3 = resp_arg0;
+ svc_result.a4 = resp_arg1;
+ svc_result.a5 = resp_arg2;
+ svc_result.a6 = resp_arg3;
+ svc_result.a7 = resp_arg4;
+ expect_ffa_svc(0xC4000070, ((uint32_t)source_id << 16) | dest_id, 0,
+ arg0, arg1, arg2, arg3, arg4, &svc_result);
+ ffa_result result = ffa_msg_send_direct_resp_64(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(0, result);
- msg_equal(0x8400006F, resp_source_id, resp_dest_id, resp_arg0,
+ msg_equal_64(0xC400006F, resp_source_id, resp_dest_id, resp_arg0,
resp_arg1, resp_arg2, resp_arg3, resp_arg4);
}
-TEST(ffa_api, ffa_msg_send_direct_resp_one_interrupt_success)
+TEST(ffa_api, ffa_msg_send_direct_resp_32_one_interrupt_success)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -690,13 +931,13 @@ TEST(ffa_api, ffa_msg_send_direct_resp_one_interrupt_success)
svc_result.a0 = 0x84000061;
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
- ffa_result result = ffa_msg_send_direct_resp(
+ ffa_result result = ffa_msg_send_direct_resp_32(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_send_direct_resp_two_interrupt_success)
+TEST(ffa_api, ffa_msg_send_direct_resp_32_two_interrupt_success)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -724,13 +965,13 @@ TEST(ffa_api, ffa_msg_send_direct_resp_two_interrupt_success)
svc_result.a0 = 0x84000061;
expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &svc_result);
- ffa_result result = ffa_msg_send_direct_resp(
+ ffa_result result = ffa_msg_send_direct_resp_32(
source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
LONGS_EQUAL(0, result);
- msg_equal(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+ msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
}
-TEST(ffa_api, ffa_msg_send_direct_resp_unknown_response)
+TEST(ffa_api, ffa_msg_send_direct_resp_32_unknown_response)
{
const uint16_t source_id = 0x1122;
const uint16_t dest_id = 0x3344;
@@ -745,7 +986,7 @@ TEST(ffa_api, ffa_msg_send_direct_resp_unknown_response)
expect_ffa_svc(0x84000070, ((uint32_t)source_id << 16) | dest_id, 0,
arg0, arg1, arg2, arg3, arg4, &svc_result);
if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
- ffa_msg_send_direct_resp(source_id, dest_id, arg0, arg1, arg2,
+ ffa_msg_send_direct_resp_32(source_id, dest_id, arg0, arg1, arg2,
arg3, arg4, &msg);
}
}
@@ -762,7 +1003,7 @@ TEST(ffa_api, ffa_mem_donate)
svc_result.a0 = 0x84000061;
svc_result.a2 = (handle_result & 0xffffffffULL);
svc_result.a3 = (handle_result >> 32);
- expect_ffa_svc(0x84000071, total_length, fragment_length,
+ expect_ffa_svc(0xc4000071, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
ffa_result result =
@@ -782,7 +1023,7 @@ TEST(ffa_api, ffa_mem_donate_error)
const uint64_t handle_result = 0xaabbccdd11223344ULL;
setup_error_response(-1);
- expect_ffa_svc(0x84000071, total_length, fragment_length,
+ expect_ffa_svc(0xc4000071, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
ffa_result result =
@@ -803,7 +1044,7 @@ TEST(ffa_api, ffa_mem_donate_unknown_response)
assert_environment_t assert_env;
svc_result.a0 = 0x12345678;
- expect_ffa_svc(0x84000071, total_length, fragment_length,
+ expect_ffa_svc(0xc4000071, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
@@ -843,7 +1084,7 @@ TEST(ffa_api, ffa_mem_lend)
svc_result.a0 = 0x84000061;
svc_result.a2 = (handle_result & 0xffffffffULL);
svc_result.a3 = (handle_result >> 32);
- expect_ffa_svc(0x84000072, total_length, fragment_length,
+ expect_ffa_svc(0xc4000072, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
ffa_result result =
@@ -863,7 +1104,7 @@ TEST(ffa_api, ffa_mem_lend_error)
const uint64_t handle_result = 0xaabbccdd11223344ULL;
setup_error_response(-1);
- expect_ffa_svc(0x84000072, total_length, fragment_length,
+ expect_ffa_svc(0xc4000072, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
ffa_result result =
@@ -884,7 +1125,7 @@ TEST(ffa_api, ffa_mem_lend_unknown_response)
assert_environment_t assert_env;
svc_result.a0 = 0x12345678;
- expect_ffa_svc(0x84000072, total_length, fragment_length,
+ expect_ffa_svc(0xc4000072, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
@@ -924,7 +1165,7 @@ TEST(ffa_api, ffa_mem_share)
svc_result.a0 = 0x84000061;
svc_result.a2 = (handle_result & 0xffffffffULL);
svc_result.a3 = (handle_result >> 32);
- expect_ffa_svc(0x84000073, total_length, fragment_length,
+ expect_ffa_svc(0xc4000073, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
ffa_result result =
@@ -944,7 +1185,7 @@ TEST(ffa_api, ffa_mem_share_error)
const uint64_t handle_result = 0xaabbccdd11223344ULL;
setup_error_response(-1);
- expect_ffa_svc(0x84000073, total_length, fragment_length,
+ expect_ffa_svc(0xc4000073, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
ffa_result result =
@@ -965,7 +1206,7 @@ TEST(ffa_api, ffa_mem_share_unknown_response)
assert_environment_t assert_env;
svc_result.a0 = 0x12345678;
- expect_ffa_svc(0x84000073, total_length, fragment_length,
+ expect_ffa_svc(0xc4000073, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
@@ -1007,7 +1248,7 @@ TEST(ffa_api, ffa_mem_retrieve_req)
svc_result.a0 = 0x84000075;
svc_result.a1 = resp_total_length_result;
svc_result.a2 = resp_frament_length_result;
- expect_ffa_svc(0x84000074, total_length, fragment_length,
+ expect_ffa_svc(0xc4000074, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
ffa_result result =
@@ -1031,7 +1272,7 @@ TEST(ffa_api, ffa_mem_retrieve_req_error)
const uint32_t resp_frament_length_result = 0x11223344;
setup_error_response(-1);
- expect_ffa_svc(0x84000074, total_length, fragment_length,
+ expect_ffa_svc(0xc4000074, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
ffa_result result =
@@ -1056,7 +1297,7 @@ TEST(ffa_api, ffa_mem_retrieve_req_unknown_response)
assert_environment_t assert_env;
svc_result.a0 = 0x12345678;
- expect_ffa_svc(0x84000074, total_length, fragment_length,
+ expect_ffa_svc(0xc4000074, total_length, fragment_length,
buffer_address, page_count, 0, 0, 0, &svc_result);
if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
@@ -1137,7 +1378,7 @@ TEST(ffa_api, ffa_mem_reclaim)
LONGS_EQUAL(0, result);
}
-TEST(ffa_api, ffa_mem_reclaimerror)
+TEST(ffa_api, ffa_mem_reclaim_error)
{
const uint64_t handle = 0x1234567812345678;
const uint32_t flags = 0x87654321;
@@ -1164,3 +1405,217 @@ TEST(ffa_api, ffa_mem_reclaim_unknown_response)
ffa_mem_reclaim(handle, flags);
}
}
+
+TEST(ffa_api, ffa_mem_perm_get)
+{
+ const void *base_addr = (const void *)0x01234567;
+ const uint32_t expected_mem_perm = 0x87654321;
+ uint32_t mem_perm = 0;
+
+ svc_result.a0 = 0x84000061;
+ svc_result.a2 = expected_mem_perm;
+ expect_ffa_svc(0x84000088, (uintptr_t)base_addr, 0, 0, 0, 0, 0, 0,
+ &svc_result);
+
+ ffa_result result = ffa_mem_perm_get(base_addr, &mem_perm);
+ LONGS_EQUAL(0, result);
+ UNSIGNED_LONGS_EQUAL(expected_mem_perm, mem_perm);
+}
+
+TEST(ffa_api, ffa_mem_perm_get_error)
+{
+ const void *base_addr = (const void *)0x01234567;
+ const uint32_t expected_mem_perm = 0x87654321;
+ uint32_t mem_perm = 0;
+
+ setup_error_response(-1);
+ expect_ffa_svc(0x84000088, (uintptr_t)base_addr, 0, 0, 0, 0, 0, 0,
+ &svc_result);
+
+ ffa_result result = ffa_mem_perm_get(base_addr, &mem_perm);
+ LONGS_EQUAL(-1, result);
+ UNSIGNED_LONGS_EQUAL(0, mem_perm);
+}
+
+TEST(ffa_api, ffa_mem_perm_get_unknown_response)
+{
+ const void *base_addr = (const void *)0x01234567;
+ const uint32_t expected_mem_perm = 0x87654321;
+ uint32_t mem_perm = 0;
+ assert_environment_t assert_env;
+
+ svc_result.a0 = 0x12345678;
+ expect_ffa_svc(0x84000088, (uintptr_t)base_addr, 0, 0, 0, 0, 0, 0,
+ &svc_result);
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_mem_perm_get(base_addr, &mem_perm);
+ }
+}
+
+TEST(ffa_api, ffa_mem_perm_set)
+{
+ const void *base_addr = (const void *)0x01234567;
+ const uint32_t page_count = 0x89abcdef;
+ const uint32_t mem_perm = 0x07;
+
+ svc_result.a0 = 0x84000061;
+ expect_ffa_svc(0x84000089, (uintptr_t)base_addr, page_count, mem_perm,
+ 0, 0, 0, 0, &svc_result);
+
+ ffa_result result = ffa_mem_perm_set(base_addr, page_count, mem_perm);
+ LONGS_EQUAL(0, result);
+}
+
+TEST(ffa_api, ffa_mem_perm_set_error)
+{
+ const void *base_addr = (const void *)0x01234567;
+ const uint32_t page_count = 0x89abcdef;
+ const uint32_t mem_perm = 0x07;
+
+ setup_error_response(-1);
+ expect_ffa_svc(0x84000089, (uintptr_t)base_addr, page_count, mem_perm,
+ 0, 0, 0, 0, &svc_result);
+
+ ffa_result result = ffa_mem_perm_set(base_addr, page_count, mem_perm);
+ LONGS_EQUAL(-1, result);
+}
+
+TEST(ffa_api, ffa_mem_perm_set_unknown_response)
+{
+ const void *base_addr = (const void *)0x01234567;
+ const uint32_t page_count = 0x89abcdef;
+ const uint32_t mem_perm = 0x07;
+ assert_environment_t assert_env;
+
+ svc_result.a0 = 0x12345678;
+ expect_ffa_svc(0x84000089, (uintptr_t)base_addr, page_count, mem_perm,
+ 0, 0, 0, 0, &svc_result);
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_mem_perm_set(base_addr, page_count, mem_perm);
+ }
+}
+
+TEST(ffa_api, ffa_mem_perm_set_invalid_mem_perm)
+{
+ const void *base_addr = (const void *)0x01234567;
+ const uint32_t page_count = 0x89abcdef;
+ const uint32_t mem_perm = 0x08;
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_mem_perm_set(base_addr, page_count, mem_perm);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_32_zero)
+{
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_32("", 0);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_32_too_long)
+{
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_32("", 25);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_32_unknown_response)
+{
+ assert_environment_t assert_env;
+ const char *message = "0";
+ const size_t length = 1;
+
+ svc_result.a0 = 0x12345678;
+ expect_ffa_svc(0x8400008A, length, 0x30, 0, 0, 0, 0, 0, &svc_result);
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_32(message, length);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_32_error)
+{
+ const char *message = "0";
+ const size_t length = 1;
+
+ setup_error_response(-1);
+ expect_ffa_svc(0x8400008A, length, 0x30, 0, 0, 0, 0, 0, &svc_result);
+ ffa_result result = ffa_console_log_32(message, length);
+ LONGS_EQUAL(-1, result);
+}
+
+TEST(ffa_api, ffa_console_log_32)
+{
+ const char *message = "0123456789abcdefghijklmn";
+ const size_t length = 24;
+
+ svc_result.a0 = 0x84000061;
+ expect_ffa_svc(0x8400008A, length, 0x33323130, 0x37363534, 0x62613938,
+ 0x66656463, 0x6A696867, 0x6E6D6C6B, &svc_result);
+ ffa_result result = ffa_console_log_32(message, length);
+ LONGS_EQUAL(0, result);
+}
+
+TEST(ffa_api, ffa_console_log_64_zero)
+{
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_64("", 0);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_64_too_long)
+{
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_64("", 49);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_64_unknown_response)
+{
+ assert_environment_t assert_env;
+ const char *message = "0";
+ const size_t length = 1;
+
+ svc_result.a0 = 0x12345678;
+ expect_ffa_svc(0xC400008A, length, 0x30, 0, 0, 0, 0, 0, &svc_result);
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_64(message, length);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_64_error)
+{
+ const char *message = "0";
+ const size_t length = 1;
+
+ setup_error_response(-1);
+ expect_ffa_svc(0xC400008A, length, 0x30, 0, 0, 0, 0, 0, &svc_result);
+ ffa_result result = ffa_console_log_64(message, length);
+ LONGS_EQUAL(-1, result);
+}
+
+TEST(ffa_api, ffa_console_log_64)
+{
+ const char *message = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ab";
+ const size_t length = 48;
+
+ svc_result.a0 = 0x84000061;
+ expect_ffa_svc(0xC400008A, length, 0x3736353433323130,
+ 0x6665646362613938, 0x6E6D6C6B6A696867,
+ 0x767574737271706F, 0x333231307A797877,
+ 0x6261393837363534, &svc_result);
+ ffa_console_log_64(message, length);
+}
diff --git a/components/messaging/ffa/libsp/test/test_mock_sp_memory_management.cpp b/components/messaging/ffa/libsp/test/test_mock_sp_memory_management.cpp
new file mode 100644
index 000000000..387b50fc2
--- /dev/null
+++ b/components/messaging/ffa/libsp/test/test_mock_sp_memory_management.cpp
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include <CppUTest/TestHarness.h>
+#include "mock_sp_memory_management.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const struct sp_memory_descriptor expected_descriptor = {
+ .sender_id = 0xfedc,
+ .memory_type = sp_memory_type_normal_memory,
+ .mem_region_attr = {.normal_memory = {
+ .cacheability = sp_cacheability_write_back,
+ .shareability = sp_shareability_inner_shareable
+ }},
+ .flags = {
+ .zero_memory = true,
+ .operation_time_slicing = true,
+ .zero_memory_after_relinquish = true,
+ .transaction_type = sp_memory_transaction_type_relayer_specified,
+ .alignment_hint = 0x2000
+ },
+ .tag = 0x0123456789abcdefULL
+};
+static const struct sp_memory_access_descriptor expected_acc_desc[] = {
+ {
+ .receiver_id = 0xfafa,
+ .instruction_access = sp_instruction_access_executable,
+ .data_access = sp_data_access_read_only
+ }, {
+ .receiver_id = 0xc1ca,
+ .instruction_access = sp_instruction_access_not_executable,
+ .data_access = sp_data_access_read_write
+ }
+};
+static const struct sp_memory_region expected_regions[2] = {
+ {.address = (void *)0x01234567, .page_count = 0x89abcdef},
+ {.address = (void *)0x12345670, .page_count = 0x9abcdef8},
+};
+static const uint64_t expected_handle = 0xabcdef0123456789ULL;
+static const void *expected_address = (const void *)0x234567879;
+static const struct sp_mem_perm expected_mem_perm = {
+ .data_access = sp_mem_perm_data_perm_read_write,
+ .instruction_access = sp_mem_perm_instruction_perm_non_executable,
+};
+
+TEST_GROUP(mock_sp_memory_management)
+{
+ TEST_SETUP()
+ {
+ memset(&descriptor, 0x00, sizeof(descriptor));
+ memset(&acc_desc, 0x00, sizeof(acc_desc));
+ memset(&regions, 0x00, sizeof(regions));
+ handle = 0;
+ supported = false;
+ }
+
+ TEST_TEARDOWN()
+ {
+ mock().checkExpectations();
+ mock().clear();
+ }
+
+ struct sp_memory_descriptor descriptor;
+ struct sp_memory_access_descriptor acc_desc[2];
+ struct sp_memory_region regions[2];
+ uint64_t handle;
+ bool supported;
+ struct ffa_mem_transaction_buffer tr_buffer;
+
+ static const sp_result result = -1;
+};
+
+TEST(mock_sp_memory_management, sp_memory_donate)
+{
+ descriptor = expected_descriptor;
+ acc_desc[0] = expected_acc_desc[0];
+ memcpy(regions, expected_regions, sizeof(regions));
+
+ expect_sp_memory_donate(&expected_descriptor, expected_acc_desc, expected_regions, 2,
+ &expected_handle, result);
+ LONGS_EQUAL(result, sp_memory_donate(&descriptor, acc_desc, regions, 2, &handle));
+
+ UNSIGNED_LONGLONGS_EQUAL(expected_handle, handle);
+}
+
+TEST(mock_sp_memory_management, sp_memory_donate_dynamic)
+{
+ descriptor = expected_descriptor;
+ acc_desc[0] = expected_acc_desc[0];
+ memcpy(regions, expected_regions, sizeof(regions));
+
+ expect_sp_memory_donate_dynamic(&expected_descriptor, expected_acc_desc, expected_regions,
+ 2, &expected_handle, result);
+ LONGS_EQUAL(result, sp_memory_donate_dynamic(&descriptor, acc_desc, regions, 2, &handle,
+ &tr_buffer));
+
+ UNSIGNED_LONGLONGS_EQUAL(expected_handle, handle);
+}
+
+TEST(mock_sp_memory_management, sp_memory_donate_dynamic_is_supported)
+{
+ const bool expected_supported = true;
+ expect_sp_memory_donate_dynamic_is_supported(&expected_supported, result);
+ LONGS_EQUAL(result, sp_memory_donate_dynamic_is_supported(&supported));
+ CHECK_TRUE(supported);
+}
+
+TEST(mock_sp_memory_management, sp_memory_lend)
+{
+ descriptor = expected_descriptor;
+ memcpy(acc_desc, expected_acc_desc, sizeof(acc_desc));
+ memcpy(regions, expected_regions, sizeof(regions));
+
+ expect_sp_memory_lend(&descriptor, acc_desc, 2, regions, 2, &expected_handle, result);
+ LONGS_EQUAL(result, sp_memory_lend(&descriptor, acc_desc, 2, regions, 2, &handle));
+ UNSIGNED_LONGLONGS_EQUAL(expected_handle, handle);
+}
+
+TEST(mock_sp_memory_management, sp_memory_lend_dynamic)
+{
+ descriptor = expected_descriptor;
+ memcpy(acc_desc, expected_acc_desc, sizeof(acc_desc));
+ memcpy(regions, expected_regions, sizeof(regions));
+
+ expect_sp_memory_lend_dynamic(&descriptor, acc_desc, 2, regions, 2, &expected_handle,
+ result);
+ LONGS_EQUAL(result, sp_memory_lend_dynamic(&descriptor, acc_desc, 2, regions, 2, &handle,
+ &tr_buffer));
+ UNSIGNED_LONGLONGS_EQUAL(expected_handle, handle);
+}
+
+TEST(mock_sp_memory_management, sp_memory_lend_dynamic_is_supported)
+{
+ const bool expected_supported = true;
+ expect_sp_memory_lend_dynamic_is_supported(&expected_supported, result);
+ LONGS_EQUAL(result, sp_memory_lend_dynamic_is_supported(&supported));
+ CHECK_TRUE(supported);
+}
+
+TEST(mock_sp_memory_management, sp_memory_share)
+{
+ descriptor = expected_descriptor;
+ memcpy(acc_desc, expected_acc_desc, sizeof(acc_desc));
+ memcpy(regions, expected_regions, sizeof(regions));
+
+ expect_sp_memory_share(&descriptor, acc_desc, 2, regions, 2, &expected_handle, result);
+ LONGS_EQUAL(result, sp_memory_share(&descriptor, acc_desc, 2, regions, 2, &handle));
+ UNSIGNED_LONGLONGS_EQUAL(expected_handle, handle);
+}
+
+TEST(mock_sp_memory_management, sp_memory_share_dynamic)
+{
+ descriptor = expected_descriptor;
+ memcpy(acc_desc, expected_acc_desc, sizeof(acc_desc));
+ memcpy(regions, expected_regions, sizeof(regions));
+
+ expect_sp_memory_share_dynamic(&descriptor, acc_desc, 2, regions, 2, &expected_handle,
+ result);
+ LONGS_EQUAL(result, sp_memory_share_dynamic(&descriptor, acc_desc, 2, regions, 2, &handle,
+ &tr_buffer));
+ UNSIGNED_LONGLONGS_EQUAL(expected_handle, handle);
+}
+
+TEST(mock_sp_memory_management, sp_memory_share_dynamic_is_supported)
+{
+ const bool expected_supported = true;
+ expect_sp_memory_share_dynamic_is_supported(&expected_supported, result);
+ LONGS_EQUAL(result, sp_memory_share_dynamic_is_supported(&supported));
+ CHECK_TRUE(supported);
+}
+
+TEST(mock_sp_memory_management, sp_memory_retrieve)
+{
+ const uint32_t expected_region_count = 1;
+ struct sp_memory_access_descriptor acc_desc = expected_acc_desc[0];
+ struct sp_memory_region region = expected_regions[0];
+ uint32_t out_region_count = 0;
+
+ descriptor = expected_descriptor;
+
+ expect_sp_memory_retrieve(&expected_descriptor, &expected_acc_desc[0],
+ &expected_acc_desc[1], &expected_regions[0],
+ &expected_regions[1], 1, &expected_region_count, expected_handle,
+ result);
+ LONGS_EQUAL(result, sp_memory_retrieve(&descriptor, &acc_desc, &region, 1,
+ &out_region_count, expected_handle));
+ MEMCMP_EQUAL(&acc_desc, &expected_acc_desc[1], sizeof(acc_desc));
+ MEMCMP_EQUAL(&region, &expected_regions[1], sizeof(region));
+ UNSIGNED_LONGS_EQUAL(expected_region_count, out_region_count);
+}
+
+TEST(mock_sp_memory_management, sp_memory_retrieve_dynamic)
+{
+ const uint32_t expected_region_count = 1;
+ struct sp_memory_access_descriptor acc_desc = expected_acc_desc[0];
+ struct sp_memory_region region = expected_regions[0];
+ uint32_t out_region_count = 0;
+
+ descriptor = expected_descriptor;
+
+ expect_sp_memory_retrieve_dynamic(&expected_descriptor, &expected_acc_desc[0],
+ &expected_acc_desc[1], &expected_regions[0],
+ &expected_regions[1], 1, &expected_region_count,
+ expected_handle, result);
+ LONGS_EQUAL(result, sp_memory_retrieve_dynamic(&descriptor, &acc_desc, &region, 1,
+ &out_region_count, expected_handle,
+ &tr_buffer));
+ MEMCMP_EQUAL(&acc_desc, &expected_acc_desc[1], sizeof(acc_desc));
+ MEMCMP_EQUAL(&region, &expected_regions[1], sizeof(region));
+ UNSIGNED_LONGS_EQUAL(expected_region_count, out_region_count);
+}
+
+TEST(mock_sp_memory_management, sp_memory_retrieve_dynamic_is_supported)
+{
+ const bool expected_supported = true;
+ expect_sp_memory_retrieve_dynamic_is_supported(&expected_supported, result);
+ LONGS_EQUAL(result, sp_memory_retrieve_dynamic_is_supported(&supported));
+ CHECK_TRUE(supported);
+}
+
+TEST(mock_sp_memory_management, sp_memory_relinquish)
+{
+ uint16_t endpoints[3] = {1, 2, 3};
+ struct sp_memory_transaction_flags flags = {0}; // TODO: flags
+
+ expect_sp_memory_relinquish(expected_handle, endpoints, 3, &flags, result);
+ LONGS_EQUAL(result, sp_memory_relinquish(expected_handle, endpoints, 3, &flags));
+}
+
+TEST(mock_sp_memory_management, sp_memory_reclaim)
+{
+ uint32_t flags = 0xffffffff;
+
+ expect_sp_memory_reclaim(expected_handle, flags, result);
+ LONGS_EQUAL(result, sp_memory_reclaim(expected_handle, flags));
+}
+
+TEST(mock_sp_memory_management, sp_memory_permission_get)
+{
+ struct sp_mem_perm mem_perm;
+
+ memset(&mem_perm, 0x00, sizeof(mem_perm));
+
+ expect_sp_memory_permission_get(expected_address, &expected_mem_perm, result);
+ LONGS_EQUAL(result, sp_memory_permission_get(expected_address, &mem_perm));
+ MEMCMP_EQUAL(&expected_mem_perm, &mem_perm, sizeof(expected_mem_perm));
+}
+
+TEST(mock_sp_memory_management, sp_memory_permission_set)
+{
+ size_t size = 0x7654;
+
+ expect_sp_memory_permission_set(expected_address, size, &expected_mem_perm, result);
+ LONGS_EQUAL(result, sp_memory_permission_set(expected_address, size, &expected_mem_perm));
+}
diff --git a/components/messaging/ffa/libsp/test/test_sp_discovery.cpp b/components/messaging/ffa/libsp/test/test_sp_discovery.cpp
index 1e615813c..5c48fe8fc 100644
--- a/components/messaging/ffa/libsp/test/test_sp_discovery.cpp
+++ b/components/messaging/ffa/libsp/test/test_sp_discovery.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
*/
#include <CppUTest/TestHarness.h>
@@ -169,18 +169,20 @@ TEST(sp_discovery, sp_discovery_partition_info_get_null_uuid)
{
struct sp_partition_info info = { 1 };
const struct sp_partition_info expected_info = { 0 };
+ uint32_t count = 1;
LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
- sp_discovery_partition_info_get(NULL, &info));
+ sp_discovery_partition_info_get(NULL, &info, &count));
MEMCMP_EQUAL(&expected_info, &info, sizeof(info));
}
TEST(sp_discovery, sp_discovery_partition_info_get_null_info)
{
struct sp_uuid uuid = { 1 };
+ uint32_t count = 0;
LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
- sp_discovery_partition_info_get(&uuid, NULL));
+ sp_discovery_partition_info_get(&uuid, NULL, &count));
}
TEST(sp_discovery, sp_discovery_partition_info_get_nil_uuid)
@@ -188,9 +190,10 @@ TEST(sp_discovery, sp_discovery_partition_info_get_nil_uuid)
struct sp_uuid uuid = { 0 };
struct sp_partition_info info = { 1 };
const struct sp_partition_info expected_info = { 0 };
+ uint32_t count = 1;
LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
- sp_discovery_partition_info_get(&uuid, &info));
+ sp_discovery_partition_info_get(&uuid, &info, &count));
MEMCMP_EQUAL(&expected_info, &info, sizeof(info));
}
@@ -199,9 +202,11 @@ TEST(sp_discovery, sp_discovery_partition_info_rx_buffer_get_fail)
struct sp_uuid uuid = { 1 };
struct sp_partition_info info = { 1 };
const struct sp_partition_info expected_info = { 0 };
+ uint32_t count = 1;
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, result);
- LONGS_EQUAL(result, sp_discovery_partition_info_get(&uuid, &info));
+ LONGS_EQUAL(result, sp_discovery_partition_info_get(&uuid, &info,
+ &count));
MEMCMP_EQUAL(&expected_info, &info, sizeof(info));
}
@@ -209,13 +214,14 @@ TEST(sp_discovery, sp_discovery_partition_info_ffa_fail)
{
struct sp_uuid uuid = { 1 };
struct ffa_uuid ffa_uuid = { 1 };
- uint32_t count = 0;
+ uint32_t count = 1;
struct sp_partition_info info = { 1 };
const struct sp_partition_info expected_info = { 0 };
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, SP_RESULT_OK);
expect_ffa_partition_info_get(&ffa_uuid, &count, result);
- LONGS_EQUAL(result, sp_discovery_partition_info_get(&uuid, &info));
+ LONGS_EQUAL(result, sp_discovery_partition_info_get(&uuid, &info,
+ &count));
MEMCMP_EQUAL(&expected_info, &info, sizeof(info));
}
@@ -223,15 +229,16 @@ TEST(sp_discovery, sp_discovery_partition_info_small_buffer)
{
struct sp_uuid uuid = { 1 };
struct ffa_uuid ffa_uuid = { 1 };
- uint32_t count =
+ uint32_t expected_count =
(rx_buffer_size / sizeof(struct ffa_partition_information)) + 1;
+ uint32_t count = 1;
struct sp_partition_info info = { 1 };
const struct sp_partition_info expected_info = { 0 };
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, SP_RESULT_OK);
- expect_ffa_partition_info_get(&ffa_uuid, &count, SP_RESULT_OK);
+ expect_ffa_partition_info_get(&ffa_uuid, &expected_count, SP_RESULT_OK);
LONGS_EQUAL(SP_RESULT_INTERNAL_ERROR,
- sp_discovery_partition_info_get(&uuid, &info));
+ sp_discovery_partition_info_get(&uuid, &info, &count));
MEMCMP_EQUAL(&expected_info, &info, sizeof(info));
}
@@ -239,15 +246,17 @@ TEST(sp_discovery, sp_discovery_partition_info_zero_count)
{
struct sp_uuid uuid = { 1 };
struct ffa_uuid ffa_uuid = { 1 };
- uint32_t count = 0;
+ uint32_t expected_count = 0;
+ uint32_t count = 1;
struct sp_partition_info info = { 1 };
const struct sp_partition_info expected_info = { 0 };
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, SP_RESULT_OK);
- expect_ffa_partition_info_get(&ffa_uuid, &count, SP_RESULT_OK);
+ expect_ffa_partition_info_get(&ffa_uuid, &expected_count, SP_RESULT_OK);
LONGS_EQUAL(SP_RESULT_NOT_FOUND,
- sp_discovery_partition_info_get(&uuid, &info));
+ sp_discovery_partition_info_get(&uuid, &info, &count));
MEMCMP_EQUAL(&expected_info, &info, sizeof(info));
+ UNSIGNED_LONGS_EQUAL(expected_count, count);
}
TEST(sp_discovery, sp_discovery_partition_info)
@@ -258,22 +267,29 @@ TEST(sp_discovery, sp_discovery_partition_info)
(rx_buffer_size / sizeof(struct ffa_partition_information));
const uint16_t expected_id = 1234;
const uint16_t expected_context_count = 23456;
- struct sp_partition_info info = { 0 };
+ struct sp_partition_info *info =
+ (struct sp_partition_info *)calloc(count, sizeof(struct sp_partition_info));
- ((struct ffa_partition_information *)rx_buffer)->partition_id =
- expected_id;
- ((struct ffa_partition_information *)rx_buffer)
- ->execution_context_count = expected_context_count;
+ for (uint32_t i = 0; i < count; i++) {
+ ((struct ffa_partition_information *)rx_buffer)[i].partition_id = expected_id + i;
+ ((struct ffa_partition_information *)rx_buffer)[i].execution_context_count = expected_context_count + i;
+ ((struct ffa_partition_information *)rx_buffer)[i].partition_properties = 0;
+ }
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, SP_RESULT_OK);
expect_ffa_partition_info_get(&ffa_uuid, &count, SP_RESULT_OK);
LONGS_EQUAL(SP_RESULT_OK,
- sp_discovery_partition_info_get(&uuid, &info));
- UNSIGNED_LONGS_EQUAL(expected_id, info.partition_id);
- UNSIGNED_LONGS_EQUAL(expected_context_count,
- info.execution_context_count);
- CHECK_FALSE(info.supports_direct_requests);
- CHECK_FALSE(info.can_send_direct_requests);
- CHECK_FALSE(info.supports_indirect_requests);
+ sp_discovery_partition_info_get(&uuid, info, &count));
+
+ for (uint32_t i = 0; i < count; i++) {
+ UNSIGNED_LONGS_EQUAL(expected_id + i, info[i].partition_id);
+ UNSIGNED_LONGS_EQUAL(expected_context_count + i,
+ info[i].execution_context_count);
+ CHECK_FALSE(info[i].supports_direct_requests);
+ CHECK_FALSE(info[i].can_send_direct_requests);
+ CHECK_FALSE(info[i].supports_indirect_requests);
+ }
+
+ free(info);
}
TEST(sp_discovery, sp_discovery_partition_info_support_direct_req)
@@ -288,7 +304,7 @@ TEST(sp_discovery, sp_discovery_partition_info_support_direct_req)
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, SP_RESULT_OK);
expect_ffa_partition_info_get(&ffa_uuid, &count, SP_RESULT_OK);
LONGS_EQUAL(SP_RESULT_OK,
- sp_discovery_partition_info_get(&uuid, &info));
+ sp_discovery_partition_info_get(&uuid, &info, &count));
CHECK_TRUE(info.supports_direct_requests);
CHECK_FALSE(info.can_send_direct_requests);
CHECK_FALSE(info.supports_indirect_requests);
@@ -306,7 +322,7 @@ TEST(sp_discovery, sp_discovery_partition_info_can_send_direct_req)
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, SP_RESULT_OK);
expect_ffa_partition_info_get(&ffa_uuid, &count, SP_RESULT_OK);
LONGS_EQUAL(SP_RESULT_OK,
- sp_discovery_partition_info_get(&uuid, &info));
+ sp_discovery_partition_info_get(&uuid, &info, &count));
CHECK_FALSE(info.supports_direct_requests);
CHECK_TRUE(info.can_send_direct_requests);
CHECK_FALSE(info.supports_indirect_requests);
@@ -324,7 +340,7 @@ TEST(sp_discovery, sp_discovery_partition_info_support_indirect_req)
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, SP_RESULT_OK);
expect_ffa_partition_info_get(&ffa_uuid, &count, SP_RESULT_OK);
LONGS_EQUAL(SP_RESULT_OK,
- sp_discovery_partition_info_get(&uuid, &info));
+ sp_discovery_partition_info_get(&uuid, &info, &count));
CHECK_FALSE(info.supports_direct_requests);
CHECK_FALSE(info.can_send_direct_requests);
CHECK_TRUE(info.supports_indirect_requests);
@@ -394,7 +410,7 @@ TEST(sp_discovery, sp_discovery_partition_info_get_all_zero_count)
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &rx_buffer_size, SP_RESULT_OK);
expect_ffa_partition_info_get(&ffa_uuid, &expected_count, SP_RESULT_OK);
- LONGS_EQUAL(SP_RESULT_OK,
+ LONGS_EQUAL(SP_RESULT_NOT_FOUND,
sp_discovery_partition_info_get_all(&info, &count));
UNSIGNED_LONGS_EQUAL(0, count);
}
diff --git a/components/messaging/ffa/libsp/test/test_sp_memory_management.cpp b/components/messaging/ffa/libsp/test/test_sp_memory_management.cpp
index 16b6e8080..46b62741a 100644
--- a/components/messaging/ffa/libsp/test/test_sp_memory_management.cpp
+++ b/components/messaging/ffa/libsp/test/test_sp_memory_management.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*/
#include <CppUTestExt/MockSupport.h>
@@ -1131,6 +1131,40 @@ TEST(sp_memory_management, sp_memory_retrieve_ffa_error)
UNSIGNED_LONGS_EQUAL(0, out_region_count);
}
+TEST(sp_memory_management, sp_memory_retrieve_ffa_rx_release_error)
+{
+ struct sp_memory_descriptor desc = SP_MEM_DESC_C(sender_id, tag);
+ struct sp_memory_access_descriptor acc_desc = { .receiver_id =
+ receiver_id };
+ struct sp_memory_region regions = { .address = ptr,
+ .page_count = page_count };
+ uint32_t in_region_count = 1;
+ uint32_t out_region_count = 1;
+ ffa_result result = FFA_ABORTED;
+ const uint32_t expected_size = get_expected_size(in_region_count);
+ const uint32_t resp_total_length = expected_size;
+ const uint32_t resp_fragment_length = expected_size;
+
+ /* Filling RX buffer */
+ ffa_init_mem_transaction_desc(&rx_mem_transaction_buffer, sender_id + 1,
+ 0, 0, handle, tag);
+ ffa_add_mem_access_desc(&rx_mem_transaction_buffer, receiver_id + 1, 0,
+ 0);
+ ffa_add_memory_region(&rx_mem_transaction_buffer, ptr, page_count);
+
+ /* Exercising */
+ expect_sp_rxtx_buffer_tx_get(&tx_buffer, &buffer_size, SP_RESULT_OK);
+ expect_sp_rxtx_buffer_rx_get(&rx_buffer, &buffer_size, SP_RESULT_OK);
+ expect_ffa_rx_release(FFA_DENIED);
+ expect_ffa_mem_retrieve_req_rxtx(expected_size, expected_size,
+ &resp_total_length,
+ &resp_fragment_length, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_FFA(FFA_DENIED),
+ sp_memory_retrieve(&desc, &acc_desc, &regions,
+ in_region_count, &out_region_count,
+ handle));
+}
+
TEST(sp_memory_management, sp_memory_retrieve_fragmented_response)
{
struct sp_memory_descriptor desc = { 0 };
@@ -1144,6 +1178,7 @@ TEST(sp_memory_management, sp_memory_retrieve_fragmented_response)
expect_sp_rxtx_buffer_tx_get(&tx_buffer, &buffer_size, SP_RESULT_OK);
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &buffer_size, SP_RESULT_OK);
+ expect_ffa_rx_release(FFA_OK);
expect_ffa_mem_retrieve_req_rxtx(expected_size, expected_size,
&resp_total_length,
&resp_fragment_length, FFA_OK);
@@ -1178,6 +1213,7 @@ TEST(sp_memory_management, sp_memory_retrieve_in_out)
/* Exercising */
expect_sp_rxtx_buffer_tx_get(&tx_buffer, &buffer_size, SP_RESULT_OK);
expect_sp_rxtx_buffer_rx_get(&rx_buffer, &buffer_size, SP_RESULT_OK);
+ expect_ffa_rx_release(FFA_OK);
expect_ffa_mem_retrieve_req_rxtx(expected_size, expected_size,
&resp_total_length,
&resp_fragment_length, FFA_OK);
@@ -1514,3 +1550,203 @@ TEST(sp_memory_management, sp_memory_reclaim)
expect_ffa_mem_reclaim(handle, flags, FFA_OK);
LONGS_EQUAL(SP_RESULT_OK, sp_memory_reclaim(handle, flags));
}
+
+TEST_GROUP(sp_memory_permission) {
+ TEST_SETUP()
+ {
+ memset(&mem_perm, 0x00, sizeof(mem_perm));
+ }
+
+ TEST_TEARDOWN()
+ {
+ mock().checkExpectations();
+ mock().clear();
+ }
+
+ const void *valid_base_address = (const void *)0xfffff000;
+ const void *invalid_base_address = (const void *)0xfffff800;
+ size_t valid_size = 0x0000f000;
+ size_t invalid_size = 0x0000f800;
+ struct sp_mem_perm mem_perm;
+};
+
+TEST(sp_memory_permission, sp_memory_permission_get_base_null)
+{
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_get(NULL, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_get_mem_perm_null)
+{
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_get(valid_base_address, NULL));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_get_invalid_address)
+{
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_get(invalid_base_address, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_get_ffa_error)
+{
+ ffa_result result = FFA_ABORTED;
+ const uint32_t raw_perm = 0x7;
+
+ expect_ffa_mem_perm_get(valid_base_address, &raw_perm, result);
+ LONGS_EQUAL(SP_RESULT_FFA(result),
+ sp_memory_permission_get(valid_base_address, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_get_reserved_data_perm)
+{
+ const uint32_t raw_perm = 0x02;
+
+ expect_ffa_mem_perm_get(valid_base_address, &raw_perm, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_INTERNAL_ERROR,
+ sp_memory_permission_get(valid_base_address, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_get_no_data_access)
+{
+ const uint32_t raw_perm = 0x00;
+
+ expect_ffa_mem_perm_get(valid_base_address, &raw_perm, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_OK,
+ sp_memory_permission_get(valid_base_address, &mem_perm));
+ CHECK_EQUAL(sp_mem_perm_data_perm_no_access, mem_perm.data_access);
+ CHECK_EQUAL(sp_mem_perm_instruction_perm_executable, mem_perm.instruction_access);
+}
+
+TEST(sp_memory_permission, sp_memory_permission_get_rw_data_access)
+{
+ const uint32_t raw_perm = 0x01;
+
+ expect_ffa_mem_perm_get(valid_base_address, &raw_perm, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_OK,
+ sp_memory_permission_get(valid_base_address, &mem_perm));
+ CHECK_EQUAL(sp_mem_perm_data_perm_read_write, mem_perm.data_access);
+ CHECK_EQUAL(sp_mem_perm_instruction_perm_executable, mem_perm.instruction_access);
+}
+
+TEST(sp_memory_permission, sp_memory_permission_get_ro_data_access)
+{
+ const uint32_t raw_perm = 0x03;
+
+ expect_ffa_mem_perm_get(valid_base_address, &raw_perm, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_OK,
+ sp_memory_permission_get(valid_base_address, &mem_perm));
+ CHECK_EQUAL(sp_mem_perm_data_perm_read_only, mem_perm.data_access);
+ CHECK_EQUAL(sp_mem_perm_instruction_perm_executable, mem_perm.instruction_access);
+}
+
+TEST(sp_memory_permission, sp_memory_permission_get_non_executable)
+{
+ const uint32_t raw_perm = 0x07;
+
+ expect_ffa_mem_perm_get(valid_base_address, &raw_perm, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_OK,
+ sp_memory_permission_get(valid_base_address, &mem_perm));
+ CHECK_EQUAL(sp_mem_perm_data_perm_read_only, mem_perm.data_access);
+ CHECK_EQUAL(sp_mem_perm_instruction_perm_non_executable, mem_perm.instruction_access);
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_base_null)
+{
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(NULL, valid_size, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_size_zero)
+{
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(valid_base_address, 0, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_mem_perm_null)
+{
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(valid_base_address, valid_size, NULL));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_mem_perm_rwx)
+{
+ mem_perm.data_access = sp_mem_perm_data_perm_read_write;
+ mem_perm.instruction_access = sp_mem_perm_instruction_perm_executable;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(valid_base_address, valid_size, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_invalid_data_perm)
+{
+ mem_perm.data_access = sp_mem_perm_data_perm_reserved;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(valid_base_address, valid_size, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_invalid_instruction_perm)
+{
+ mem_perm.instruction_access = (sp_mem_perm_instruction_access_permission)0xff;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(valid_base_address, valid_size, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_invalid_base_addr)
+{
+ mem_perm.data_access = sp_mem_perm_data_perm_read_write;
+ mem_perm.instruction_access = sp_mem_perm_instruction_perm_non_executable;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(invalid_base_address, valid_size, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_invalid_region_size)
+{
+ mem_perm.data_access = sp_mem_perm_data_perm_read_write;
+ mem_perm.instruction_access = sp_mem_perm_instruction_perm_non_executable;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(valid_base_address, invalid_size, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_too_large_region_size)
+{
+ mem_perm.data_access = sp_mem_perm_data_perm_read_write;
+ mem_perm.instruction_access = sp_mem_perm_instruction_perm_non_executable;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_memory_permission_set(valid_base_address, 0x100000000000UL, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_ronx)
+{
+ mem_perm.data_access = sp_mem_perm_data_perm_read_only;
+ mem_perm.instruction_access = sp_mem_perm_instruction_perm_non_executable;
+
+ expect_ffa_mem_perm_set(valid_base_address, valid_size / 4096, 0x07, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_OK,
+ sp_memory_permission_set(valid_base_address, valid_size, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_rwnx)
+{
+ mem_perm.data_access = sp_mem_perm_data_perm_read_write;
+ mem_perm.instruction_access = sp_mem_perm_instruction_perm_non_executable;
+
+ expect_ffa_mem_perm_set(valid_base_address, valid_size / 4096, 0x05, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_OK,
+ sp_memory_permission_set(valid_base_address, valid_size, &mem_perm));
+}
+
+TEST(sp_memory_permission, sp_memory_permission_set_rox)
+{
+ mem_perm.data_access = sp_mem_perm_data_perm_read_only;
+ mem_perm.instruction_access = sp_mem_perm_instruction_perm_executable;
+
+ expect_ffa_mem_perm_set(valid_base_address, valid_size / 4096, 0x03, FFA_OK);
+ LONGS_EQUAL(SP_RESULT_OK,
+ sp_memory_permission_set(valid_base_address, valid_size, &mem_perm));
+}
diff --git a/components/messaging/ffa/libsp/test/test_sp_messaging.cpp b/components/messaging/ffa/libsp/test/test_sp_messaging.cpp
index 78bf8bf47..15aba0134 100644
--- a/components/messaging/ffa/libsp/test/test_sp_messaging.cpp
+++ b/components/messaging/ffa/libsp/test/test_sp_messaging.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*/
#include <CppUTest/TestHarness.h>
@@ -10,11 +10,9 @@
#include "mock_ffa_api.h"
#include "../include/sp_messaging.h"
-#define SP_MSG_ARG_OFFSET (1)
-
#if FFA_DIRECT_MSG_ROUTING_EXTENSION
-#define ROUTING_EXT_RC_BIT BIT(0)
-#define ROUTING_EXT_ERR_BIT BIT(1)
+#define ROUTING_EXT_RC_BIT BIT(31)
+#define ROUTING_EXT_ERR_BIT BIT(30)
#endif
TEST_GROUP(sp_messaging)
@@ -32,16 +30,25 @@ TEST_GROUP(sp_messaging)
mock().clear();
}
- void copy_sp_to_ffa_args(const uint32_t sp_args[], uint32_t ffa_args[])
+ void copy_sp_to_ffa_args_32(const uint32_t sp_args[], uint32_t ffa_args[])
{
int i = 0;
for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
- ffa_args[i + SP_MSG_ARG_OFFSET] = sp_args[i];
+ ffa_args[i] = sp_args[i];
}
}
- void fill_ffa_msg(struct ffa_direct_msg * msg)
+ void copy_sp_to_ffa_args_64(const uint64_t sp_args[], uint64_t ffa_args[])
+ {
+ int i = 0;
+
+ for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+ ffa_args[i] = sp_args[i];
+ }
+ }
+
+ void fill_ffa_msg_32(struct ffa_direct_msg * msg)
{
int i = 0;
@@ -49,20 +56,45 @@ TEST_GROUP(sp_messaging)
msg->source_id = source_id;
msg->destination_id = dest_id;
- msg->args[0] = 0;
for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
- msg->args[i + SP_MSG_ARG_OFFSET] = args[i];
+ msg->args.args32[i] = args32[i];
+ }
+ }
+
+ void fill_ffa_msg_64(struct ffa_direct_msg * msg)
+ {
+ int i = 0;
+
+ msg->function_id = FFA_MSG_SEND_DIRECT_REQ_64;
+ msg->source_id = source_id;
+ msg->destination_id = dest_id;
+
+ for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+ msg->args.args64[i] = args64[i];
}
}
- void fill_sp_msg(struct sp_msg * msg)
+ void fill_sp_msg_32(struct sp_msg * msg)
{
int i = 0;
msg->source_id = source_id;
msg->destination_id = dest_id;
+ msg->is_64bit_message = false;
for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
- msg->args[i] = args[i + SP_MSG_ARG_OFFSET];
+ msg->args.args32[i] = args32[i];
+ }
+ }
+
+ void fill_sp_msg_64(struct sp_msg * msg)
+ {
+ int i = 0;
+
+ msg->source_id = source_id;
+ msg->destination_id = dest_id;
+ msg->is_64bit_message = true;
+ for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+ msg->args.args64[i] = args64[i];
}
}
@@ -74,10 +106,19 @@ TEST_GROUP(sp_messaging)
UNSIGNED_LONGS_EQUAL(ffa_msg->source_id, sp_msg->source_id);
UNSIGNED_LONGS_EQUAL(ffa_msg->destination_id,
sp_msg->destination_id);
- for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
- UNSIGNED_LONGS_EQUAL(
- ffa_msg->args[i + SP_MSG_ARG_OFFSET],
- sp_msg->args[i]);
+ CHECK_EQUAL(FFA_IS_64_BIT_FUNC(ffa_msg->function_id), sp_msg->is_64bit_message);
+ if (sp_msg->is_64bit_message) {
+ for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+ UNSIGNED_LONGLONGS_EQUAL(
+ ffa_msg->args.args64[i],
+ sp_msg->args.args64[i]);
+ }
+ } else {
+ for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+ UNSIGNED_LONGS_EQUAL(
+ ffa_msg->args.args32[i],
+ sp_msg->args.args32[i]);
+ }
}
}
@@ -87,7 +128,7 @@ TEST_GROUP(sp_messaging)
struct ffa_direct_msg expected_ffa_req = { 0 };
struct sp_msg req = { 0 };
- fill_ffa_msg(&expected_ffa_req);
+ fill_ffa_msg_32(&expected_ffa_req);
expected_ffa_req.source_id = source_id;
expected_ffa_req.destination_id = dest_id;
expect_ffa_msg_wait(&expected_ffa_req, FFA_OK);
@@ -103,8 +144,11 @@ TEST_GROUP(sp_messaging)
const uint16_t source_id = 0x1234;
const uint16_t dest_id = 0x5678;
- const uint32_t args[SP_MSG_ARG_COUNT] = { 0x01234567, 0x12345678,
- 0x23456789, 0x3456789a };
+ const uint32_t args32[SP_MSG_ARG_COUNT] = { 0x01234567, 0x12345678,
+ 0x23456789, 0x3456789a, 0xbcdef012 };
+ const uint64_t args64[SP_MSG_ARG_COUNT] = { 0x0123456776543210, 0x1234567887654321,
+ 0x2345678998765432, 0x3456789aa9876543,
+ 0x210fedcba9876543 };
const sp_result result = -1;
const sp_msg empty_sp_msg = (const sp_msg){ 0 };
};
@@ -126,7 +170,7 @@ TEST(sp_messaging, sp_msg_wait_ffa_error)
TEST(sp_messaging, sp_msg_wait)
{
- fill_ffa_msg(&ffa_msg);
+ fill_ffa_msg_32(&ffa_msg);
expect_ffa_msg_wait(&ffa_msg, FFA_OK);
LONGS_EQUAL(SP_RESULT_OK, sp_msg_wait(&req));
@@ -139,12 +183,12 @@ TEST(sp_messaging, sp_msg_wait_deny_rc_failure)
struct ffa_direct_msg rc_msg = { 0 };
ffa_result result = FFA_ABORTED;
- fill_ffa_msg(&rc_msg);
- rc_msg.args[0] = ROUTING_EXT_RC_BIT;
+ fill_ffa_msg_32(&rc_msg);
+ rc_msg.args.args32[0] = ROUTING_EXT_RC_BIT;
expect_ffa_msg_wait(&rc_msg, FFA_OK);
- fill_ffa_msg(&ffa_msg);
- expect_ffa_msg_send_direct_resp(
+ fill_ffa_msg_32(&ffa_msg);
+ expect_ffa_msg_send_direct_resp_32(
rc_msg.destination_id, rc_msg.source_id,
ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
SP_RESULT_FFA(FFA_DENIED), 0, 0, 0, &ffa_msg, result);
@@ -157,12 +201,12 @@ TEST(sp_messaging, sp_msg_wait_deny_rc)
{
struct ffa_direct_msg rc_msg = { 0 };
- fill_ffa_msg(&rc_msg);
- rc_msg.args[0] = ROUTING_EXT_RC_BIT;
+ fill_ffa_msg_32(&rc_msg);
+ rc_msg.args.args32[0] = ROUTING_EXT_RC_BIT;
expect_ffa_msg_wait(&rc_msg, FFA_OK);
- fill_ffa_msg(&ffa_msg);
- expect_ffa_msg_send_direct_resp(
+ fill_ffa_msg_32(&ffa_msg);
+ expect_ffa_msg_send_direct_resp_32(
rc_msg.destination_id, rc_msg.source_id,
ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
SP_RESULT_FFA(FFA_DENIED), 0, 0, 0, &ffa_msg, FFA_OK);
@@ -191,10 +235,10 @@ TEST(sp_messaging, sp_msg_send_direct_req_ffa_error)
ffa_result result = FFA_ABORTED;
uint32_t expected_ffa_args[5] = { 0 };
- fill_sp_msg(&req);
+ fill_sp_msg_32(&req);
memset(&resp, 0x5a, sizeof(resp));
- copy_sp_to_ffa_args(req.args, expected_ffa_args);
- expect_ffa_msg_send_direct_req(
+ copy_sp_to_ffa_args_32(req.args.args32, expected_ffa_args);
+ expect_ffa_msg_send_direct_req_32(
req.source_id, req.destination_id, expected_ffa_args[0],
expected_ffa_args[1], expected_ffa_args[2],
expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, result);
@@ -203,14 +247,30 @@ TEST(sp_messaging, sp_msg_send_direct_req_ffa_error)
MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
}
-TEST(sp_messaging, sp_msg_send_direct_req_msg)
+TEST(sp_messaging, sp_msg_send_direct_req_msg_32)
{
uint32_t expected_ffa_args[5] = { 0 };
- fill_sp_msg(&req);
- fill_ffa_msg(&ffa_msg);
- copy_sp_to_ffa_args(req.args, expected_ffa_args);
- expect_ffa_msg_send_direct_req(
+ fill_sp_msg_32(&req);
+ fill_ffa_msg_32(&ffa_msg);
+ copy_sp_to_ffa_args_32(req.args.args32, expected_ffa_args);
+ expect_ffa_msg_send_direct_req_32(
+ req.source_id, req.destination_id, expected_ffa_args[0],
+ expected_ffa_args[1], expected_ffa_args[2],
+ expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&req, &resp));
+ ffa_and_sp_msg_equal(&ffa_msg, &resp);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_msg_64)
+{
+ uint64_t expected_ffa_args[5] = { 0 };
+
+ fill_sp_msg_64(&req);
+ fill_ffa_msg_64(&ffa_msg);
+ copy_sp_to_ffa_args_64(req.args.args64, expected_ffa_args);
+ expect_ffa_msg_send_direct_req_64(
req.source_id, req.destination_id, expected_ffa_args[0],
expected_ffa_args[1], expected_ffa_args[2],
expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
@@ -223,10 +283,10 @@ TEST(sp_messaging, sp_msg_send_direct_req_success)
{
uint32_t expected_ffa_args[5] = { 0 };
- fill_sp_msg(&req);
+ fill_sp_msg_32(&req);
ffa_msg.function_id = FFA_SUCCESS_32;
- copy_sp_to_ffa_args(req.args, expected_ffa_args);
- expect_ffa_msg_send_direct_req(
+ copy_sp_to_ffa_args_32(req.args.args32, expected_ffa_args);
+ expect_ffa_msg_send_direct_req_32(
req.source_id, req.destination_id, expected_ffa_args[0],
expected_ffa_args[1], expected_ffa_args[2],
expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
@@ -236,6 +296,17 @@ TEST(sp_messaging, sp_msg_send_direct_req_success)
}
#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+TEST(sp_messaging, sp_msg_send_direct_req_rc_bits_conflict)
+{
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg_32(&sp_req);
+ sp_req.args.args32[0] |= ROUTING_EXT_RC_BIT;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS, sp_msg_send_direct_req(&sp_req, &sp_resp));
+}
+
TEST(sp_messaging, sp_msg_send_direct_req_rc_forwarding_success)
{
const uint16_t root_id = 1;
@@ -248,54 +319,54 @@ TEST(sp_messaging, sp_msg_send_direct_req_rc_forwarding_success)
sp_msg sp_req = { 0 };
sp_msg sp_resp = { 0 };
- fill_sp_msg(&sp_req);
+ fill_sp_msg_32(&sp_req);
sp_req.source_id = own_id;
sp_req.destination_id = rc_root_id;
req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
req.source_id = own_id;
req.destination_id = rc_root_id;
- copy_sp_to_ffa_args(sp_req.args, req.args);
+ copy_sp_to_ffa_args_32(sp_req.args.args32, req.args.args32);
- fill_ffa_msg(&rc_req);
+ fill_ffa_msg_32(&rc_req);
rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
rc_req.source_id = rc_root_id;
rc_req.destination_id = own_id;
- rc_req.args[0] = ROUTING_EXT_RC_BIT;
+ rc_req.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_ffa_msg(&rc_resp);
+ fill_ffa_msg_32(&rc_resp);
rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
rc_resp.source_id = root_id;
rc_resp.destination_id = own_id;
- rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+ rc_resp.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_sp_msg(&sp_resp);
+ fill_sp_msg_32(&sp_resp);
sp_resp.source_id = rc_root_id;
sp_resp.destination_id = own_id;
resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
resp.source_id = rc_root_id;
resp.destination_id = own_id;
- copy_sp_to_ffa_args(sp_resp.args, resp.args);
+ copy_sp_to_ffa_args_32(sp_resp.args.args32, resp.args.args32);
/* Initial request to current SP to set own_id */
wait_and_receive_request(root_id, own_id);
/* Sending request and receiving RC request from RC root */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
- req.args[2], req.args[3], req.args[4],
- &rc_req, FFA_OK);
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, req.args.args32[0],
+ req.args.args32[1], req.args.args32[2],
+ req.args.args32[3], req.args.args32[4], &rc_req, FFA_OK);
/* Forwarding RC request to root and receiving RC response */
- expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
- rc_req.args[1], rc_req.args[2],
- rc_req.args[3], rc_req.args[4],
+ expect_ffa_msg_send_direct_resp_32(own_id, root_id, rc_req.args.args32[0],
+ rc_req.args.args32[1], rc_req.args.args32[2],
+ rc_req.args.args32[3], rc_req.args.args32[4],
&rc_resp, FFA_OK);
/* Fowarding RC response to RC root and receiving response */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
- rc_resp.args[1], rc_resp.args[2],
- rc_resp.args[3], rc_resp.args[4], &resp,
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, rc_resp.args.args32[0],
+ rc_resp.args.args32[1], rc_resp.args.args32[2],
+ rc_resp.args.args32[3], rc_resp.args.args32[4], &resp,
FFA_OK);
LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
@@ -312,29 +383,30 @@ TEST(sp_messaging, sp_msg_send_direct_req_rc_error)
sp_msg sp_req = { 0 };
sp_msg sp_resp = { 0 };
- fill_sp_msg(&sp_req);
+ fill_sp_msg_32(&sp_req);
sp_req.source_id = own_id;
sp_req.destination_id = rc_root_id;
req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
req.source_id = own_id;
req.destination_id = rc_root_id;
- copy_sp_to_ffa_args(sp_req.args, req.args);
+ copy_sp_to_ffa_args_32(sp_req.args.args32, req.args.args32);
- fill_ffa_msg(&rc_err);
+ fill_ffa_msg_32(&rc_err);
rc_err.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
rc_err.source_id = rc_root_id;
rc_err.destination_id = own_id;
- rc_err.args[0] = ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT;
- rc_err.args[1] = result;
+ rc_err.args.args32[0] = ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT;
+ rc_err.args.args32[1] = result;
/* Initial request to current SP to set own_id */
wait_and_receive_request(root_id, own_id);
/* Sending request and receiving RC request from RC root */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
- req.args[2], req.args[3], req.args[4],
- &rc_err, FFA_OK);
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, req.args.args32[0],
+ req.args.args32[1], req.args.args32[2],
+ req.args.args32[3], req.args.args32[4],
+ &rc_err, FFA_OK);
LONGS_EQUAL(SP_RESULT_FFA(result),
sp_msg_send_direct_req(&sp_req, &sp_resp));
@@ -354,64 +426,65 @@ TEST(sp_messaging, sp_msg_send_direct_req_rc_forwarding_success_deny_request)
sp_msg sp_req = { 0 };
sp_msg sp_resp = { 0 };
- fill_sp_msg(&sp_req);
+ fill_sp_msg_32(&sp_req);
sp_req.source_id = own_id;
sp_req.destination_id = rc_root_id;
req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
req.source_id = own_id;
req.destination_id = rc_root_id;
- copy_sp_to_ffa_args(sp_req.args, req.args);
+ copy_sp_to_ffa_args_32(sp_req.args.args32, req.args.args32);
- fill_ffa_msg(&rc_req);
+ fill_ffa_msg_32(&rc_req);
rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
rc_req.source_id = rc_root_id;
rc_req.destination_id = own_id;
- rc_req.args[0] = ROUTING_EXT_RC_BIT;
+ rc_req.args.args32[0] = ROUTING_EXT_RC_BIT;
request_to_deny.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
request_to_deny.source_id = root_id;
request_to_deny.destination_id = own_id;
- request_to_deny.args[0] = 0;
+ request_to_deny.args.args32[0] = 0;
- fill_ffa_msg(&rc_resp);
+ fill_ffa_msg_32(&rc_resp);
rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
rc_resp.source_id = root_id;
rc_resp.destination_id = own_id;
- rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+ rc_resp.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_sp_msg(&sp_resp);
+ fill_sp_msg_32(&sp_resp);
sp_resp.source_id = rc_root_id;
sp_resp.destination_id = own_id;
resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
resp.source_id = rc_root_id;
resp.destination_id = own_id;
- copy_sp_to_ffa_args(sp_resp.args, resp.args);
+ copy_sp_to_ffa_args_32(sp_resp.args.args32, resp.args.args32);
/* Initial request to current SP to set own_id */
wait_and_receive_request(root_id, own_id);
/* Sending request and receiving RC request from RC root */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
- req.args[2], req.args[3], req.args[4],
- &rc_req, FFA_OK);
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, req.args.args32[0],
+ req.args.args32[1], req.args.args32[2],
+ req.args.args32[3], req.args.args32[4],
+ &rc_req, FFA_OK);
/* Forwarding RC request to root and receiving a request to deny */
- expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
- rc_req.args[1], rc_req.args[2],
- rc_req.args[3], rc_req.args[4],
+ expect_ffa_msg_send_direct_resp_32(own_id, root_id, rc_req.args.args32[0],
+ rc_req.args.args32[1], rc_req.args.args32[2],
+ rc_req.args.args32[3], rc_req.args.args32[4],
&request_to_deny, FFA_OK);
/* Sending error to root and receiving RC response */
- expect_ffa_msg_send_direct_resp(
+ expect_ffa_msg_send_direct_resp_32(
own_id, root_id, ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &rc_resp, FFA_OK);
/* Fowarding RC response to RC root and receiving response */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
- rc_resp.args[1], rc_resp.args[2],
- rc_resp.args[3], rc_resp.args[4], &resp,
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, rc_resp.args.args32[0],
+ rc_resp.args.args32[1], rc_resp.args.args32[2],
+ rc_resp.args.args32[3], rc_resp.args.args32[4], &resp,
FFA_OK);
LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
@@ -431,65 +504,66 @@ TEST(sp_messaging, sp_msg_send_direct_req_rc_forwarding_success_invalid_req_src)
sp_msg sp_req = { 0 };
sp_msg sp_resp = { 0 };
- fill_sp_msg(&sp_req);
+ fill_sp_msg_32(&sp_req);
sp_req.source_id = own_id;
sp_req.destination_id = rc_root_id;
req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
req.source_id = own_id;
req.destination_id = rc_root_id;
- copy_sp_to_ffa_args(sp_req.args, req.args);
+ copy_sp_to_ffa_args_32(sp_req.args.args32, req.args.args32);
- fill_ffa_msg(&rc_req);
+ fill_ffa_msg_32(&rc_req);
rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
rc_req.source_id = rc_root_id;
rc_req.destination_id = own_id;
- rc_req.args[0] = ROUTING_EXT_RC_BIT;
+ rc_req.args.args32[0] = ROUTING_EXT_RC_BIT;
request_to_deny.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
/* This source ID should be denied in the current state. */
request_to_deny.source_id = rc_root_id;
request_to_deny.destination_id = own_id;
- request_to_deny.args[0] = ROUTING_EXT_RC_BIT;
+ request_to_deny.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_ffa_msg(&rc_resp);
+ fill_ffa_msg_32(&rc_resp);
rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
rc_resp.source_id = root_id;
rc_resp.destination_id = own_id;
- rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+ rc_resp.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_sp_msg(&sp_resp);
+ fill_sp_msg_32(&sp_resp);
sp_resp.source_id = rc_root_id;
sp_resp.destination_id = own_id;
resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
resp.source_id = rc_root_id;
resp.destination_id = own_id;
- copy_sp_to_ffa_args(sp_resp.args, resp.args);
+ copy_sp_to_ffa_args_32(sp_resp.args.args32, resp.args.args32);
/* Initial request to current SP to set own_id */
wait_and_receive_request(root_id, own_id);
/* Sending request and receiving RC request from RC root */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
- req.args[2], req.args[3], req.args[4],
- &rc_req, FFA_OK);
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, req.args.args32[0],
+ req.args.args32[1], req.args.args32[2],
+ req.args.args32[3], req.args.args32[4],
+ &rc_req, FFA_OK);
/* Forwarding RC request to root and receiving RC response */
- expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
- rc_req.args[1], rc_req.args[2],
- rc_req.args[3], rc_req.args[4],
+ expect_ffa_msg_send_direct_resp_32(own_id, root_id, rc_req.args.args32[0],
+ rc_req.args.args32[1], rc_req.args.args32[2],
+ rc_req.args.args32[3], rc_req.args.args32[4],
&request_to_deny, FFA_OK);
/* Sending error to root and receiving RC response */
- expect_ffa_msg_send_direct_resp(
+ expect_ffa_msg_send_direct_resp_32(
own_id, rc_root_id, ROUTING_EXT_ERR_BIT | ROUTING_EXT_RC_BIT,
SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &rc_resp, FFA_OK);
/* Fowarding RC response to RC root and receiving response */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
- rc_resp.args[1], rc_resp.args[2],
- rc_resp.args[3], rc_resp.args[4], &resp,
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, rc_resp.args.args32[0],
+ rc_resp.args.args32[1], rc_resp.args.args32[2],
+ rc_resp.args.args32[3], rc_resp.args.args32[4], &resp,
FFA_OK);
LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
@@ -509,58 +583,59 @@ TEST(sp_messaging, sp_msg_send_direct_req_deny_fail_wait_success)
sp_msg sp_req = { 0 };
sp_msg sp_resp = { 0 };
- fill_sp_msg(&sp_req);
+ fill_sp_msg_32(&sp_req);
sp_req.source_id = own_id;
sp_req.destination_id = rc_root_id;
req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
req.source_id = own_id;
req.destination_id = rc_root_id;
- copy_sp_to_ffa_args(sp_req.args, req.args);
+ copy_sp_to_ffa_args_32(sp_req.args.args32, req.args.args32);
- fill_ffa_msg(&rc_req);
+ fill_ffa_msg_32(&rc_req);
rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
rc_req.source_id = rc_root_id;
rc_req.destination_id = own_id;
- rc_req.args[0] = ROUTING_EXT_RC_BIT;
+ rc_req.args.args32[0] = ROUTING_EXT_RC_BIT;
request_to_deny.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
/* This source ID should be denied in the current state. */
request_to_deny.source_id = rc_root_id;
request_to_deny.destination_id = own_id;
- request_to_deny.args[0] = ROUTING_EXT_RC_BIT;
+ request_to_deny.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_ffa_msg(&rc_resp);
+ fill_ffa_msg_32(&rc_resp);
rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
rc_resp.source_id = root_id;
rc_resp.destination_id = own_id;
- rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+ rc_resp.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_sp_msg(&sp_resp);
+ fill_sp_msg_32(&sp_resp);
sp_resp.source_id = rc_root_id;
sp_resp.destination_id = own_id;
resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
resp.source_id = rc_root_id;
resp.destination_id = own_id;
- copy_sp_to_ffa_args(sp_resp.args, resp.args);
+ copy_sp_to_ffa_args_32(sp_resp.args.args32, resp.args.args32);
/* Initial request to current SP to set own_id */
wait_and_receive_request(root_id, own_id);
/* Sending request and receiving RC request from RC root */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
- req.args[2], req.args[3], req.args[4],
- &rc_req, FFA_OK);
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, req.args.args32[0],
+ req.args.args32[1], req.args.args32[2],
+ req.args.args32[3], req.args.args32[4],
+ &rc_req, FFA_OK);
/* Forwarding RC request to root and receiving RC response */
- expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
- rc_req.args[1], rc_req.args[2],
- rc_req.args[3], rc_req.args[4],
+ expect_ffa_msg_send_direct_resp_32(own_id, root_id, rc_req.args.args32[0],
+ rc_req.args.args32[1], rc_req.args.args32[2],
+ rc_req.args.args32[3], rc_req.args.args32[4],
&request_to_deny, FFA_OK);
/* Sending error to root which fails */
- expect_ffa_msg_send_direct_resp(
+ expect_ffa_msg_send_direct_resp_32(
own_id, rc_root_id, (ROUTING_EXT_ERR_BIT | ROUTING_EXT_RC_BIT),
SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &rc_resp, FFA_DENIED);
@@ -568,9 +643,9 @@ TEST(sp_messaging, sp_msg_send_direct_req_deny_fail_wait_success)
expect_ffa_msg_wait(&rc_resp, FFA_OK);
/* Fowarding RC response to RC root and receiving response */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
- rc_resp.args[1], rc_resp.args[2],
- rc_resp.args[3], rc_resp.args[4], &resp,
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, rc_resp.args.args32[0],
+ rc_resp.args.args32[1], rc_resp.args.args32[2],
+ rc_resp.args.args32[3], rc_resp.args.args32[4], &resp,
FFA_OK);
LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
@@ -590,58 +665,59 @@ TEST(sp_messaging, sp_msg_send_direct_req_deny_fail_wait_fail_forwarding)
sp_msg sp_req = { 0 };
sp_msg sp_resp = { 0 };
- fill_sp_msg(&sp_req);
+ fill_sp_msg_32(&sp_req);
sp_req.source_id = own_id;
sp_req.destination_id = rc_root_id;
req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
req.source_id = own_id;
req.destination_id = rc_root_id;
- copy_sp_to_ffa_args(sp_req.args, req.args);
+ copy_sp_to_ffa_args_32(sp_req.args.args32, req.args.args32);
- fill_ffa_msg(&rc_req);
+ fill_ffa_msg_32(&rc_req);
rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
rc_req.source_id = rc_root_id;
rc_req.destination_id = own_id;
- rc_req.args[0] = ROUTING_EXT_RC_BIT;
+ rc_req.args.args32[0] = ROUTING_EXT_RC_BIT;
request_to_deny.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
/* This source ID should be denied in the current state. */
request_to_deny.source_id = rc_root_id;
request_to_deny.destination_id = own_id;
- request_to_deny.args[0] = ROUTING_EXT_RC_BIT;
+ request_to_deny.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_ffa_msg(&rc_resp);
+ fill_ffa_msg_32(&rc_resp);
rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
rc_resp.source_id = root_id;
rc_resp.destination_id = own_id;
- rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+ rc_resp.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_sp_msg(&sp_resp);
+ fill_sp_msg_32(&sp_resp);
sp_resp.source_id = rc_root_id;
sp_resp.destination_id = own_id;
resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
resp.source_id = rc_root_id;
resp.destination_id = own_id;
- copy_sp_to_ffa_args(sp_resp.args, resp.args);
+ copy_sp_to_ffa_args_32(sp_resp.args.args32, resp.args.args32);
/* Initial request to current SP to set own_id */
wait_and_receive_request(root_id, own_id);
/* Sending request and receiving RC request from RC root */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
- req.args[2], req.args[3], req.args[4],
- &rc_req, FFA_OK);
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, req.args.args32[0],
+ req.args.args32[1], req.args.args32[2],
+ req.args.args32[3], req.args.args32[4],
+ &rc_req, FFA_OK);
/* Forwarding RC request to root and receiving RC response */
- expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
- rc_req.args[1], rc_req.args[2],
- rc_req.args[3], rc_req.args[4],
+ expect_ffa_msg_send_direct_resp_32(own_id, root_id, rc_req.args.args32[0],
+ rc_req.args.args32[1], rc_req.args.args32[2],
+ rc_req.args.args32[3], rc_req.args.args32[4],
&request_to_deny, FFA_OK);
/* Sending error to root which fails */
- expect_ffa_msg_send_direct_resp(
+ expect_ffa_msg_send_direct_resp_32(
own_id, rc_root_id, ROUTING_EXT_ERR_BIT | ROUTING_EXT_RC_BIT,
SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &rc_resp, FFA_DENIED);
@@ -649,7 +725,7 @@ TEST(sp_messaging, sp_msg_send_direct_req_deny_fail_wait_fail_forwarding)
expect_ffa_msg_wait(&rc_resp, result);
/* Fowarding RC error as FFA_MSG_WAIT failed */
- expect_ffa_msg_send_direct_req(
+ expect_ffa_msg_send_direct_req_32(
own_id, rc_root_id, (ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT),
result, 0, 0, 0, &resp, FFA_OK);
@@ -670,52 +746,53 @@ TEST(sp_messaging, sp_msg_send_direct_req_rc_return_rc_error_msg)
sp_msg sp_resp = { 0 };
ffa_result result = FFA_ABORTED;
- fill_sp_msg(&sp_req);
+ fill_sp_msg_32(&sp_req);
sp_req.source_id = own_id;
sp_req.destination_id = rc_root_id;
req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
req.source_id = own_id;
req.destination_id = rc_root_id;
- copy_sp_to_ffa_args(sp_req.args, req.args);
+ copy_sp_to_ffa_args_32(sp_req.args.args32, req.args.args32);
- fill_ffa_msg(&rc_req);
+ fill_ffa_msg_32(&rc_req);
rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
rc_req.source_id = rc_root_id;
rc_req.destination_id = own_id;
- rc_req.args[0] = ROUTING_EXT_RC_BIT;
+ rc_req.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_ffa_msg(&rc_resp);
+ fill_ffa_msg_32(&rc_resp);
rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
rc_resp.source_id = root_id;
rc_resp.destination_id = own_id;
- rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+ rc_resp.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_sp_msg(&sp_resp);
+ fill_sp_msg_32(&sp_resp);
sp_resp.source_id = rc_root_id;
sp_resp.destination_id = own_id;
resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
resp.source_id = rc_root_id;
resp.destination_id = own_id;
- copy_sp_to_ffa_args(sp_resp.args, resp.args);
+ copy_sp_to_ffa_args_32(sp_resp.args.args32, resp.args.args32);
/* Initial request to current SP to set own_id */
wait_and_receive_request(root_id, own_id);
/* Sending request and receiving RC request from RC root */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
- req.args[2], req.args[3], req.args[4],
- &rc_req, FFA_OK);
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, req.args.args32[0],
+ req.args.args32[1], req.args.args32[2],
+ req.args.args32[3], req.args.args32[4],
+ &rc_req, FFA_OK);
/* Forwarding RC request to root and receiving RC response */
- expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
- rc_req.args[1], rc_req.args[2],
- rc_req.args[3], rc_req.args[4],
+ expect_ffa_msg_send_direct_resp_32(own_id, root_id, rc_req.args.args32[0],
+ rc_req.args.args32[1], rc_req.args.args32[2],
+ rc_req.args.args32[3], rc_req.args.args32[4],
&rc_resp, result);
/* Fowarding RC error to RC root and receiving response */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id,
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id,
ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
SP_RESULT_FFA(result), 0, 0, 0, &resp,
FFA_OK);
@@ -737,54 +814,55 @@ TEST(sp_messaging, sp_msg_send_direct_req_rc_return_resp_fail)
sp_msg sp_resp = { 0 };
ffa_result result = FFA_ABORTED;
- fill_sp_msg(&sp_req);
+ fill_sp_msg_32(&sp_req);
sp_req.source_id = own_id;
sp_req.destination_id = rc_root_id;
req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
req.source_id = own_id;
req.destination_id = rc_root_id;
- copy_sp_to_ffa_args(sp_req.args, req.args);
+ copy_sp_to_ffa_args_32(sp_req.args.args32, req.args.args32);
- fill_ffa_msg(&rc_req);
+ fill_ffa_msg_32(&rc_req);
rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
rc_req.source_id = rc_root_id;
rc_req.destination_id = own_id;
- rc_req.args[0] = ROUTING_EXT_RC_BIT;
+ rc_req.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_ffa_msg(&rc_resp);
+ fill_ffa_msg_32(&rc_resp);
rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
rc_resp.source_id = root_id;
rc_resp.destination_id = own_id;
- rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+ rc_resp.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_sp_msg(&sp_resp);
+ fill_sp_msg_32(&sp_resp);
sp_resp.source_id = rc_root_id;
sp_resp.destination_id = own_id;
resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
resp.source_id = rc_root_id;
resp.destination_id = own_id;
- copy_sp_to_ffa_args(sp_resp.args, resp.args);
+ copy_sp_to_ffa_args_32(sp_resp.args.args32, resp.args.args32);
/* Initial request to current SP to set own_id */
wait_and_receive_request(root_id, own_id);
/* Sending request and receiving RC request from RC root */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
- req.args[2], req.args[3], req.args[4],
- &rc_req, FFA_OK);
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, req.args.args32[0],
+ req.args.args32[1], req.args.args32[2],
+ req.args.args32[3], req.args.args32[4],
+ &rc_req, FFA_OK);
/* Forwarding RC request to root and receiving RC response */
- expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
- rc_req.args[1], rc_req.args[2],
- rc_req.args[3], rc_req.args[4],
+ expect_ffa_msg_send_direct_resp_32(own_id, root_id, rc_req.args.args32[0],
+ rc_req.args.args32[1], rc_req.args.args32[2],
+ rc_req.args.args32[3], rc_req.args.args32[4],
&rc_resp, FFA_OK);
/* Fowarding RC response to RC root and receiving response */
- expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
- rc_resp.args[1], rc_resp.args[2],
- rc_resp.args[3], rc_resp.args[4], &resp,
+ expect_ffa_msg_send_direct_req_32(own_id, rc_root_id, rc_resp.args.args32[0],
+ rc_resp.args.args32[1], rc_resp.args.args32[2],
+ rc_resp.args.args32[3], rc_resp.args.args32[4], &resp,
result);
LONGS_EQUAL(SP_RESULT_FFA(result),
@@ -812,10 +890,11 @@ TEST(sp_messaging, sp_msg_send_direct_resp_ffa_error)
ffa_result result = FFA_ABORTED;
uint32_t expected_ffa_args[5] = { 0 };
- fill_sp_msg(&resp);
+ fill_sp_msg_32(&resp);
memset(&req, 0x5a, sizeof(req));
- copy_sp_to_ffa_args(resp.args, expected_ffa_args);
- expect_ffa_msg_send_direct_resp(
+ req.is_64bit_message = false;
+ copy_sp_to_ffa_args_32(resp.args.args32, expected_ffa_args);
+ expect_ffa_msg_send_direct_resp_32(
resp.source_id, resp.destination_id, expected_ffa_args[0],
expected_ffa_args[1], expected_ffa_args[2],
expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, result);
@@ -825,14 +904,14 @@ TEST(sp_messaging, sp_msg_send_direct_resp_ffa_error)
MEMCMP_EQUAL(&empty_sp_msg, &req, sizeof(empty_sp_msg));
}
-TEST(sp_messaging, sp_msg_send_direct_resp_msg)
+TEST(sp_messaging, sp_msg_send_direct_resp_msg_32)
{
uint32_t expected_ffa_args[5] = { 0 };
- fill_sp_msg(&resp);
- fill_ffa_msg(&ffa_msg);
- copy_sp_to_ffa_args(resp.args, expected_ffa_args);
- expect_ffa_msg_send_direct_resp(
+ fill_sp_msg_32(&resp);
+ fill_ffa_msg_32(&ffa_msg);
+ copy_sp_to_ffa_args_32(resp.args.args32, expected_ffa_args);
+ expect_ffa_msg_send_direct_resp_32(
resp.source_id, resp.destination_id, expected_ffa_args[0],
expected_ffa_args[1], expected_ffa_args[2],
expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
@@ -841,15 +920,32 @@ TEST(sp_messaging, sp_msg_send_direct_resp_msg)
ffa_and_sp_msg_equal(&ffa_msg, &req);
}
+TEST(sp_messaging, sp_msg_send_direct_resp_msg_64)
+{
+ uint64_t expected_ffa_args[5] = { 0 };
+
+ fill_sp_msg_64(&resp);
+ fill_ffa_msg_64(&ffa_msg);
+ copy_sp_to_ffa_args_64(resp.args.args64, expected_ffa_args);
+ expect_ffa_msg_send_direct_resp_64(
+ resp.source_id, resp.destination_id, expected_ffa_args[0],
+ expected_ffa_args[1], expected_ffa_args[2],
+ expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_resp(&resp, &req));
+ ffa_and_sp_msg_equal(&ffa_msg, &req);
+}
+
+
TEST(sp_messaging, sp_msg_send_direct_resp_success)
{
uint32_t expected_ffa_args[5] = { 0 };
- fill_sp_msg(&req);
- fill_sp_msg(&resp);
+ fill_sp_msg_32(&req);
+ fill_sp_msg_32(&resp);
ffa_msg.function_id = FFA_SUCCESS_32;
- copy_sp_to_ffa_args(resp.args, expected_ffa_args);
- expect_ffa_msg_send_direct_resp(
+ copy_sp_to_ffa_args_32(resp.args.args32, expected_ffa_args);
+ expect_ffa_msg_send_direct_resp_32(
resp.source_id, resp.destination_id, expected_ffa_args[0],
expected_ffa_args[1], expected_ffa_args[2],
expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
@@ -859,25 +955,36 @@ TEST(sp_messaging, sp_msg_send_direct_resp_success)
}
#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+TEST(sp_messaging, sp_msg_send_direct_resp_rc_bits_conflict)
+{
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg_32(&sp_resp);
+ sp_resp.args.args32[0] |= ROUTING_EXT_RC_BIT;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS, sp_msg_send_direct_resp(&sp_resp, &sp_req));
+}
+
TEST(sp_messaging, sp_msg_send_direct_resp_deny_rc_failure)
{
uint32_t expected_ffa_args[5] = { 0 };
struct ffa_direct_msg rc_msg = { 0 };
- fill_sp_msg(&resp);
+ fill_sp_msg_32(&resp);
- fill_ffa_msg(&rc_msg);
- rc_msg.args[0] = ROUTING_EXT_RC_BIT;
+ fill_ffa_msg_32(&rc_msg);
+ rc_msg.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_ffa_msg(&ffa_msg);
- copy_sp_to_ffa_args(resp.args, expected_ffa_args);
+ fill_ffa_msg_32(&ffa_msg);
+ copy_sp_to_ffa_args_32(resp.args.args32, expected_ffa_args);
- expect_ffa_msg_send_direct_resp(
+ expect_ffa_msg_send_direct_resp_32(
resp.source_id, resp.destination_id, expected_ffa_args[0],
expected_ffa_args[1], expected_ffa_args[2],
expected_ffa_args[3], expected_ffa_args[4], &rc_msg, FFA_OK);
- expect_ffa_msg_send_direct_resp(
+ expect_ffa_msg_send_direct_resp_32(
rc_msg.destination_id, rc_msg.source_id,
ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
SP_RESULT_FFA(FFA_DENIED), 0, 0, 0, &ffa_msg, result);
@@ -892,21 +999,20 @@ TEST(sp_messaging, sp_msg_send_direct_resp_deny_rc)
uint32_t expected_ffa_args[5] = { 0 };
struct ffa_direct_msg rc_msg = { 0 };
- fill_sp_msg(&resp);
+ fill_sp_msg_32(&resp);
- fill_ffa_msg(&rc_msg);
- rc_msg.args[0] = ROUTING_EXT_RC_BIT;
+ fill_ffa_msg_32(&rc_msg);
+ rc_msg.args.args32[0] = ROUTING_EXT_RC_BIT;
- fill_ffa_msg(&ffa_msg);
- copy_sp_to_ffa_args(resp.args, expected_ffa_args);
+ fill_ffa_msg_32(&ffa_msg);
+ copy_sp_to_ffa_args_32(resp.args.args32, expected_ffa_args);
- expect_ffa_msg_send_direct_resp(resp.source_id, resp.destination_id, 0,
- expected_ffa_args[1],
- expected_ffa_args[2],
- expected_ffa_args[3],
- expected_ffa_args[4], &rc_msg, FFA_OK);
+ expect_ffa_msg_send_direct_resp_32(resp.source_id, resp.destination_id,
+ expected_ffa_args[0], expected_ffa_args[1],
+ expected_ffa_args[2], expected_ffa_args[3],
+ expected_ffa_args[4], &rc_msg, FFA_OK);
- expect_ffa_msg_send_direct_resp(
+ expect_ffa_msg_send_direct_resp_32(
rc_msg.destination_id, rc_msg.source_id,
ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
SP_RESULT_FFA(FFA_DENIED), 0, 0, 0, &ffa_msg, FFA_OK);
@@ -929,17 +1035,30 @@ TEST(sp_messaging, sp_msg_send_rc_req_resp_null)
MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
}
+TEST(sp_messaging, sp_msg_send_direct_rc_resp_rc_bits_conflict)
+{
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg_32(&sp_req);
+ sp_req.args.args32[0] |= ROUTING_EXT_RC_BIT;
+
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS, sp_msg_send_rc_req(&sp_req, &sp_resp));
+}
+
TEST(sp_messaging, sp_msg_send_rc_req_ffa_error)
{
ffa_result result = FFA_ABORTED;
- fill_sp_msg(&resp);
+ fill_sp_msg_32(&resp);
memset(&req, 0x5a, sizeof(req));
- fill_ffa_msg(&ffa_msg);
+ req.args.args32[0] &= ~0xc0000000;
+ req.is_64bit_message = false;
+ fill_ffa_msg_32(&ffa_msg);
- expect_ffa_msg_send_direct_resp(req.source_id, req.destination_id,
- ROUTING_EXT_RC_BIT, req.args[0],
- req.args[1], req.args[2], req.args[3],
+ expect_ffa_msg_send_direct_resp_32(req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT | req.args.args32[0], req.args.args32[1],
+ req.args.args32[2], req.args.args32[3], req.args.args32[4],
&ffa_msg, result);
LONGS_EQUAL(SP_RESULT_FFA(result), sp_msg_send_rc_req(&req, &resp));
@@ -953,22 +1072,22 @@ TEST(sp_messaging, sp_msg_send_rc_req_deny_fail_wait_fail)
wait_and_receive_request(root_id, own_id);
- fill_sp_msg(&req);
+ fill_sp_msg_32(&req);
req.source_id = own_id;
req.destination_id = root_id;
- fill_ffa_msg(&ffa_msg);
+ fill_ffa_msg_32(&ffa_msg);
ffa_msg.source_id = root_id;
ffa_msg.destination_id = own_id;
/* Should be RC message so it will be denied */
- ffa_msg.args[0] = 0;
+ ffa_msg.args.args32[0] = 0;
- expect_ffa_msg_send_direct_resp(req.source_id, req.destination_id,
- ROUTING_EXT_RC_BIT, req.args[0],
- req.args[1], req.args[2], req.args[3],
+ expect_ffa_msg_send_direct_resp_32(req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT | req.args.args32[0], req.args.args32[1],
+ req.args.args32[2], req.args.args32[3], req.args.args32[4],
&ffa_msg, FFA_OK);
- expect_ffa_msg_send_direct_resp(
+ expect_ffa_msg_send_direct_resp_32(
req.source_id, req.destination_id,
ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &ffa_msg, result);
@@ -987,19 +1106,19 @@ TEST(sp_messaging, sp_msg_send_rc_req_rc_error)
wait_and_receive_request(root_id, own_id);
- fill_sp_msg(&req);
+ fill_sp_msg_32(&req);
req.source_id = own_id;
req.destination_id = root_id;
- fill_ffa_msg(&ffa_msg);
+ fill_ffa_msg_32(&ffa_msg);
ffa_msg.source_id = root_id;
ffa_msg.destination_id = own_id;
- ffa_msg.args[0] = ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT;
- ffa_msg.args[1] = sp_err;
+ ffa_msg.args.args32[0] = ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT;
+ ffa_msg.args.args32[1] = sp_err;
- expect_ffa_msg_send_direct_resp(req.source_id, req.destination_id,
- ROUTING_EXT_RC_BIT, req.args[0],
- req.args[1], req.args[2], req.args[3],
+ expect_ffa_msg_send_direct_resp_32(req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT | req.args.args32[0], req.args.args32[1],
+ req.args.args32[2], req.args.args32[3], req.args.args32[4],
&ffa_msg, FFA_OK);
LONGS_EQUAL(sp_err, sp_msg_send_rc_req(&req, &resp));
@@ -1013,18 +1132,18 @@ TEST(sp_messaging, sp_msg_send_rc_req_success)
wait_and_receive_request(root_id, own_id);
- fill_sp_msg(&req);
+ fill_sp_msg_32(&req);
req.source_id = own_id;
req.destination_id = root_id;
- fill_ffa_msg(&ffa_msg);
+ fill_ffa_msg_32(&ffa_msg);
ffa_msg.source_id = root_id;
ffa_msg.destination_id = own_id;
- ffa_msg.args[0] = ROUTING_EXT_RC_BIT;
+ ffa_msg.args.args32[0] = ROUTING_EXT_RC_BIT | req.args.args32[0];
- expect_ffa_msg_send_direct_resp(req.source_id, req.destination_id,
- ROUTING_EXT_RC_BIT, req.args[0],
- req.args[1], req.args[2], req.args[3],
+ expect_ffa_msg_send_direct_resp_32(req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT | req.args.args32[0], req.args.args32[1],
+ req.args.args32[2], req.args.args32[3], req.args.args32[4],
&ffa_msg, FFA_OK);
LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_rc_req(&req, &resp));
diff --git a/components/messaging/ffa/libsp/test/test_sp_rxtx.cpp b/components/messaging/ffa/libsp/test/test_sp_rxtx.cpp
index a26d30113..15685d2c0 100644
--- a/components/messaging/ffa/libsp/test/test_sp_rxtx.cpp
+++ b/components/messaging/ffa/libsp/test/test_sp_rxtx.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*/
#include <CppUTest/TestHarness.h>
@@ -40,7 +40,7 @@ TEST_GROUP(sp_rxtx)
[FFA_FEATURES_RXTX_MAP_GRANULARITY_INDEX] =
(granularity & FFA_FEATURES_RXTX_MAP_GRANULARITY_MASK)
<< FFA_FEATURES_RXTX_MAP_GRANULARITY_SHIFT;
- expect_ffa_features(FFA_RXTX_MAP_32, &props, result);
+ expect_ffa_features(FFA_RXTX_MAP_64, &props, result);
}
void do_successful_mapping()
@@ -318,7 +318,7 @@ TEST(sp_rxtx, sp_rxtx_buffer_alignment_boundary_get_ffa_error)
props.interface_properties[FFA_FEATURES_RXTX_MAP_GRANULARITY_INDEX] =
0 << FFA_FEATURES_RXTX_MAP_GRANULARITY_SHIFT;
- expect_ffa_features(FFA_RXTX_MAP_32, &props, result);
+ expect_ffa_features(FFA_RXTX_MAP_64, &props, result);
LONGS_EQUAL(SP_RESULT_FFA(result),
sp_rxtx_buffer_alignment_boundary_get(&alignment));
@@ -332,7 +332,7 @@ TEST(sp_rxtx, sp_rxtx_buffer_alignment_boundary_get_4k)
props.interface_properties[FFA_FEATURES_RXTX_MAP_GRANULARITY_INDEX] =
0 << FFA_FEATURES_RXTX_MAP_GRANULARITY_SHIFT;
- expect_ffa_features(FFA_RXTX_MAP_32, &props, FFA_OK);
+ expect_ffa_features(FFA_RXTX_MAP_64, &props, FFA_OK);
LONGS_EQUAL(SP_RESULT_OK,
sp_rxtx_buffer_alignment_boundary_get(&alignment));
@@ -346,7 +346,7 @@ TEST(sp_rxtx, sp_rxtx_buffer_alignment_boundary_get_64k)
props.interface_properties[FFA_FEATURES_RXTX_MAP_GRANULARITY_INDEX] =
1 << FFA_FEATURES_RXTX_MAP_GRANULARITY_SHIFT;
- expect_ffa_features(FFA_RXTX_MAP_32, &props, FFA_OK);
+ expect_ffa_features(FFA_RXTX_MAP_64, &props, FFA_OK);
LONGS_EQUAL(SP_RESULT_OK,
sp_rxtx_buffer_alignment_boundary_get(&alignment));
@@ -360,7 +360,7 @@ TEST(sp_rxtx, sp_rxtx_buffer_alignment_boundary_get_16k)
props.interface_properties[FFA_FEATURES_RXTX_MAP_GRANULARITY_INDEX] =
2 << FFA_FEATURES_RXTX_MAP_GRANULARITY_SHIFT;
- expect_ffa_features(FFA_RXTX_MAP_32, &props, FFA_OK);
+ expect_ffa_features(FFA_RXTX_MAP_64, &props, FFA_OK);
LONGS_EQUAL(SP_RESULT_OK,
sp_rxtx_buffer_alignment_boundary_get(&alignment));
@@ -375,7 +375,7 @@ TEST(sp_rxtx, sp_rxtx_buffer_alignment_boundary_get_reserved)
props.interface_properties[FFA_FEATURES_RXTX_MAP_GRANULARITY_INDEX] =
3 << FFA_FEATURES_RXTX_MAP_GRANULARITY_SHIFT;
- expect_ffa_features(FFA_RXTX_MAP_32, &props, FFA_OK);
+ expect_ffa_features(FFA_RXTX_MAP_64, &props, FFA_OK);
LONGS_EQUAL(SP_RESULT_INTERNAL_ERROR,
sp_rxtx_buffer_alignment_boundary_get(&alignment));
diff --git a/components/messaging/ffa/libsp/tests.cmake b/components/messaging/ffa/libsp/tests.cmake
index d851442d5..eb0b41ec8 100644
--- a/components/messaging/ffa/libsp/tests.cmake
+++ b/components/messaging/ffa/libsp/tests.cmake
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,10 +9,11 @@ include(UnitTest)
unit_test_add_suite(
NAME libsp_mock_assert
SOURCES
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_assert.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/test_mock_assert.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_assert.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/test/test_mock_assert.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -21,10 +22,11 @@ unit_test_add_suite(
unit_test_add_suite(
NAME libsp_mock_ffa_internal_api
SOURCES
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_internal_api.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/test_mock_ffa_internal_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_ffa_internal_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/test/test_mock_ffa_internal_api.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -35,12 +37,13 @@ unit_test_add_suite(
SOURCES
${CMAKE_CURRENT_LIST_DIR}/test/test_ffa_api.cpp
${CMAKE_CURRENT_LIST_DIR}/test/test_ffa_memory_descriptors.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_internal_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_ffa_internal_api.cpp
${CMAKE_CURRENT_LIST_DIR}/ffa.c
${CMAKE_CURRENT_LIST_DIR}/ffa_memory_descriptors.c
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_assert.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_assert.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -49,10 +52,11 @@ unit_test_add_suite(
unit_test_add_suite(
NAME libsp_mock_ffa_api
SOURCES
- ${CMAKE_CURRENT_LIST_DIR}/test/test_mock_ffa_api.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/test/test_mock_ffa_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_ffa_api.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -62,10 +66,11 @@ unit_test_add_suite(
NAME libsp_sp_rxtx
SOURCES
${CMAKE_CURRENT_LIST_DIR}/test/test_sp_rxtx.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_ffa_api.cpp
${CMAKE_CURRENT_LIST_DIR}/sp_rxtx.c
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -74,10 +79,11 @@ unit_test_add_suite(
unit_test_add_suite(
NAME libsp_mock_sp_rxtx
SOURCES
- ${CMAKE_CURRENT_LIST_DIR}/test/test_mock_sp_rxtx.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_sp_rxtx.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/test/test_mock_sp_rxtx.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_sp_rxtx.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -88,10 +94,24 @@ unit_test_add_suite(
SOURCES
${CMAKE_CURRENT_LIST_DIR}/test/test_sp_discovery.cpp
${CMAKE_CURRENT_LIST_DIR}/sp_discovery.c
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_api.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_sp_rxtx.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_ffa_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_sp_rxtx.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
+ ${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
+ COMPILE_DEFINITIONS
+ -DARM64
+)
+
+unit_test_add_suite(
+ NAME libsp_mock_sp_discovery
+ SOURCES
+ ${CMAKE_CURRENT_LIST_DIR}/mock/test/test_mock_sp_discovery.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_sp_discovery.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -103,11 +123,25 @@ unit_test_add_suite(
${CMAKE_CURRENT_LIST_DIR}/test/test_sp_memory_management.cpp
${CMAKE_CURRENT_LIST_DIR}/sp_memory_management.c
${CMAKE_CURRENT_LIST_DIR}/ffa_memory_descriptors.c
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_assert.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_api.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_sp_rxtx.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_assert.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_ffa_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_sp_rxtx.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
+ ${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
+ COMPILE_DEFINITIONS
+ -DARM64
+)
+
+unit_test_add_suite(
+ NAME libsp_mock_sp_memory_management
+ SOURCES
+ ${CMAKE_CURRENT_LIST_DIR}/test/test_mock_sp_memory_management.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_sp_memory_management.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -119,9 +153,10 @@ unit_test_add_suite(
${CMAKE_CURRENT_LIST_DIR}/test/test_sp_memory_management_internals.cpp
${CMAKE_CURRENT_LIST_DIR}/test/sp_memory_management_internals.yml
${CMAKE_CURRENT_LIST_DIR}/ffa_memory_descriptors.c
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_assert.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_assert.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
@@ -131,24 +166,40 @@ unit_test_add_suite(
NAME libsp_sp_messaging
SOURCES
${CMAKE_CURRENT_LIST_DIR}/test/test_sp_messaging.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_ffa_api.cpp
${CMAKE_CURRENT_LIST_DIR}/sp_messaging.c
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
+ ${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
+ COMPILE_DEFINITIONS
+ -DARM64
+)
+
+unit_test_add_suite(
+ NAME libsp_mock_sp_messaging
+ SOURCES
+ ${CMAKE_CURRENT_LIST_DIR}/mock/test/test_mock_sp_messaging.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_sp_messaging.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
+ -DFFA_DIRECT_MSG_ROUTING_EXTENSION=1
)
unit_test_add_suite(
NAME libsp_sp_messaging_with_routing_extension
SOURCES
${CMAKE_CURRENT_LIST_DIR}/test/test_sp_messaging.cpp
- ${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_api.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mock/mock_ffa_api.cpp
${CMAKE_CURRENT_LIST_DIR}/sp_messaging.c
${CMAKE_CURRENT_LIST_DIR}/ffa_direct_msg_routing_extension.c
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_LIST_DIR}/include/
+ ${CMAKE_CURRENT_LIST_DIR}/mock
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
diff --git a/components/messaging/openamp/sp/component.cmake b/components/messaging/openamp/sp/component.cmake
new file mode 100644
index 000000000..cee76a025
--- /dev/null
+++ b/components/messaging/openamp/sp/component.cmake
@@ -0,0 +1,24 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+ "${CMAKE_CURRENT_LIST_DIR}/openamp_messenger_api.h"
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/openamp_messenger.c"
+ "${CMAKE_CURRENT_LIST_DIR}/openamp_virtio.c"
+ "${CMAKE_CURRENT_LIST_DIR}/openamp_mhu.c"
+ )
+
+target_include_directories(${TGT}
+ PUBLIC
+ "${CMAKE_CURRENT_LIST_DIR}"
+ )
diff --git a/components/messaging/openamp/sp/openamp_messenger.c b/components/messaging/openamp/sp/openamp_messenger.c
new file mode 100644
index 000000000..2b77ea45a
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_messenger.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <trace.h>
+#include "openamp_messenger.h"
+#include "openamp_messenger_api.h"
+#include "openamp_mhu.h"
+#include "openamp_virtio.h"
+#include <protocols/rpc/common/packed-c/status.h>
+
+#define OPENAMP_TRANSACTION_IDLE 0x0
+#define OPENAMP_TRANSACTION_INPROGRESS 0x1
+#define OPENAMP_TRANSACTION_INVOKED 0x2
+
+int openamp_messenger_call_begin(struct openamp_messenger *openamp,
+ uint8_t **req_buf, size_t req_len)
+{
+ const struct openamp_platform_ops *ops = openamp->platform_ops;
+ int ret;
+
+ if (!openamp)
+ return -EINVAL;
+
+ ops = openamp->platform_ops;
+ if (!req_buf) {
+ EMSG("openamp: call_begin: not req_buf");
+ return -EINVAL;
+ }
+
+ if (req_len > UINT32_MAX || req_len == 0) {
+ EMSG("openamp: call_begin: resp_len invalid: %lu", req_len);
+ return -EINVAL;
+ }
+
+ if (openamp->status != OPENAMP_TRANSACTION_IDLE) {
+ EMSG("openamp: call_begin: transaction not idle");
+ return -EINVAL;
+ }
+
+ ret = ops->platform_call_begin(openamp, req_buf, req_len);
+ if (ret < 0) {
+ EMSG("openamp: call_begin: platform begin failed: %d", ret);
+ return -EINVAL;
+ }
+
+ openamp->status = OPENAMP_TRANSACTION_INPROGRESS;
+
+ return 0;
+}
+
+int openamp_messenger_call_invoke(struct openamp_messenger *openamp,
+ uint8_t **resp_buf, size_t *resp_len)
+{
+ const struct openamp_platform_ops *ops;
+ int ret;
+
+ if (!openamp || !resp_buf || !resp_len) {
+ EMSG("openamp: call_invoke: invalid arguments");
+ return -EINVAL;
+ }
+
+ if (openamp->status != OPENAMP_TRANSACTION_INPROGRESS) {
+ EMSG("openamp: call_invoke: transaction needed to be started");
+ return -ENOTCONN;
+ }
+
+ ops = openamp->platform_ops;
+
+ ret = ops->platform_call_invoke(openamp, resp_buf, resp_len);
+ if (ret < 0)
+ return ret;
+
+ openamp->status = OPENAMP_TRANSACTION_INVOKED;
+
+ return 0;
+}
+
+void openamp_messenger_call_end(struct openamp_messenger *openamp)
+{
+ const struct openamp_platform_ops *ops;
+
+ if (!openamp)
+ return;
+
+ if (openamp->status == OPENAMP_TRANSACTION_IDLE) {
+ EMSG("openamp: call_end: transaction idle");
+ return;
+ }
+
+ ops = openamp->platform_ops;
+
+ ops->platform_call_end(openamp);
+
+ openamp->status = OPENAMP_TRANSACTION_IDLE;
+}
+
+void *openamp_messenger_phys_to_virt(struct openamp_messenger *openamp,
+ void *pa)
+{
+ const struct openamp_platform_ops *ops = openamp->platform_ops;
+
+ return ops->platform_phys_to_virt(openamp, pa);
+}
+
+void *openamp_messenger_virt_to_phys(struct openamp_messenger *openamp,
+ void *va)
+{
+ const struct openamp_platform_ops *ops = openamp->platform_ops;
+
+ return ops->platform_virt_to_phys(openamp, va);
+}
+
+static const struct openamp_platform_ops openamp_virtio_ops = {
+ .transport_init = openamp_mhu_init,
+ .transport_deinit = openamp_mhu_deinit,
+ .transport_notify = openamp_mhu_notify_peer,
+ .transport_receive = openamp_mhu_receive,
+ .platform_init = openamp_virtio_init,
+ .platform_call_begin = openamp_virtio_call_begin,
+ .platform_call_invoke = openamp_virtio_call_invoke,
+ .platform_call_end = openamp_virtio_call_end,
+ .platform_virt_to_phys = openamp_virtio_virt_to_phys,
+ .platform_phys_to_virt = openamp_virtio_phys_to_virt,
+};
+
+int openamp_messenger_init(struct openamp_messenger *openamp)
+{
+ const struct openamp_platform_ops *ops;
+ int ret;
+
+ if (openamp->ref_count)
+ return 0;
+
+ openamp->platform_ops = &openamp_virtio_ops;
+
+ ops = openamp->platform_ops;
+
+ ret = ops->transport_init(openamp);
+ if (ret < 0)
+ return ret;
+
+ ret = ops->platform_init(openamp);
+ if (ret < 0)
+ goto denit_transport;
+
+ openamp->ref_count++;
+
+ return 0;
+
+denit_transport:
+ ops->transport_deinit(openamp);
+
+ return ret;
+}
+
+void openamp_messenger_deinit(struct openamp_messenger *openamp)
+{
+ if (--openamp->ref_count)
+ return;
+}
diff --git a/components/messaging/openamp/sp/openamp_messenger.h b/components/messaging/openamp/sp/openamp_messenger.h
new file mode 100644
index 000000000..e863c4f34
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_messenger.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef OPENAMP_MESSENGER_H
+#define OPENAMP_MESSENGER_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct openamp_messenger;
+
+struct openamp_platform_ops {
+ int (*transport_init)(struct openamp_messenger *openamp);
+ int (*transport_deinit)(struct openamp_messenger *openamp);
+ int (*transport_notify)(struct openamp_messenger *openamp);
+ int (*transport_receive)(struct openamp_messenger *openamp);
+ int (*platform_init)(struct openamp_messenger *openamp);
+ int (*platform_deinit)(struct openamp_messenger *openamp);
+ int (*platform_call_begin)(struct openamp_messenger *openamp,
+ uint8_t **req_buf, size_t req_len);
+ int (*platform_call_invoke)(struct openamp_messenger *openamp,
+ uint8_t **resp_buf, size_t *resp_len);
+ int (*platform_call_end)(struct openamp_messenger *openamp);
+ void *(*platform_virt_to_phys)(struct openamp_messenger *openamp,
+ void *va);
+ void *(*platform_phys_to_virt)(struct openamp_messenger *openamp,
+ void *pa);
+};
+
+#endif
diff --git a/components/messaging/openamp/sp/openamp_messenger_api.h b/components/messaging/openamp/sp/openamp_messenger_api.h
new file mode 100644
index 000000000..61ab37aa9
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_messenger_api.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef OPENAMP_MESSENGER_API_H
+#define OPENAMP_MESSENGER_API_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "openamp_messenger.h"
+
+struct openamp_messenger {
+ const struct openamp_platform_ops *platform_ops;
+ uint32_t ref_count;
+ uint8_t status;
+
+ void *transport;
+ void *platform;
+};
+
+int openamp_messenger_init(struct openamp_messenger *openamp);
+void openamp_messenger_deinit(struct openamp_messenger *openamp);
+void openamp_messenger_call_end(struct openamp_messenger *openamp);
+int openamp_messenger_call_invoke(struct openamp_messenger *openamp,
+ uint8_t **resp_buf, size_t *resp_len);
+int openamp_messenger_call_begin(struct openamp_messenger *openamp,
+ uint8_t **req_buf, size_t req_len);
+
+void *openamp_messenger_phys_to_virt(struct openamp_messenger *openamp,
+ void *pa);
+void *openamp_messenger_virt_to_phys(struct openamp_messenger *openamp,
+ void *va);
+#endif
diff --git a/components/messaging/openamp/sp/openamp_mhu.c b/components/messaging/openamp/sp/openamp_mhu.c
new file mode 100644
index 000000000..bafba3e37
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_mhu.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <config/interface/config_store.h>
+#include <config/interface/config_blob.h>
+#include <platform/interface/device_region.h>
+#include <platform/drivers/arm/mhu_driver/mhu_v2.h>
+#include <trace.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+
+#include "openamp_messenger_api.h"
+
+#define MHU_V_2_NOTIFY_CHANNEL 0
+#define MHU_V_2_NOTIFY_VALUE 0xff
+
+struct openamp_mhu {
+ struct device_region rx_region;
+ struct device_region tx_region;
+ struct mhu_v2_x_dev_t rx_dev;
+ struct mhu_v2_x_dev_t tx_dev;
+};
+
+static int openamp_mhu_device_get(const char *dev,
+ struct device_region *dev_region)
+{
+ bool found;
+
+ found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
+ dev_region, sizeof(*dev_region));
+ if (!found)
+ return -EINVAL;
+
+ if (!dev_region->base_addr)
+ return -EINVAL;
+
+ IMSG("mhu: device region found: %s addr: 0x%p size: %lu", dev,
+ (void *)dev_region->base_addr, dev_region->io_region_size);
+
+ return 0;
+}
+
+int openamp_mhu_receive(struct openamp_messenger *openamp)
+{
+ struct mhu_v2_x_dev_t *rx_dev;
+ enum mhu_v2_x_error_t ret;
+ struct openamp_mhu *mhu;
+ uint32_t channel = 0;
+ uint32_t irq_status;
+
+ if (!openamp->transport) {
+ EMSG("openamp: mhu: receive transport not initialized");
+ return -EINVAL;
+ }
+
+ mhu = openamp->transport;
+ rx_dev = &mhu->rx_dev;
+
+ irq_status = 0;
+
+ do {
+ irq_status = mhu_v2_x_get_interrupt_status(rx_dev);
+ } while(!irq_status);
+
+ ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
+
+ ret = mhu_v2_x_channel_clear(rx_dev, channel);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: failed to clear channel: %d", channel);
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+int openamp_mhu_notify_peer(struct openamp_messenger *openamp)
+{
+ struct mhu_v2_x_dev_t *tx_dev;
+ enum mhu_v2_x_error_t ret;
+ struct openamp_mhu *mhu;
+ uint32_t access_ready;
+
+ if (!openamp->transport) {
+ EMSG("openamp: mhu: notify transport not initialized");
+ return -EINVAL;
+ }
+
+ mhu = openamp->transport;
+ tx_dev = &mhu->tx_dev;
+
+ ret = mhu_v2_x_set_access_request(tx_dev);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: set access request failed");
+ return -EPROTO;
+ }
+
+ do {
+ ret = mhu_v2_x_get_access_ready(tx_dev, &access_ready);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: failed to get access_ready");
+ return -EPROTO;
+ }
+ } while (!access_ready);
+
+ ret = mhu_v2_x_channel_send(tx_dev, MHU_V_2_NOTIFY_CHANNEL,
+ MHU_V_2_NOTIFY_VALUE);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: failed send over channel");
+ return -EPROTO;
+ }
+
+ ret = mhu_v2_x_reset_access_request(tx_dev);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: failed reset access request");
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+int openamp_mhu_init(struct openamp_messenger *openamp)
+{
+ struct mhu_v2_x_dev_t *rx_dev;
+ struct mhu_v2_x_dev_t *tx_dev;
+ struct openamp_mhu *mhu;
+ int ret;
+
+ /* if we already have initialized skip this */
+ if (openamp->transport)
+ return 0;
+
+ mhu = malloc(sizeof(*mhu));
+ if (!mhu)
+ return -1;
+
+ ret = openamp_mhu_device_get("mhu-sender", &mhu->tx_region);
+ if (ret < 0)
+ goto free_mhu;
+
+ ret = openamp_mhu_device_get("mhu-receiver", &mhu->rx_region);
+ if (ret < 0)
+ goto free_mhu;
+
+ rx_dev = &mhu->rx_dev;
+ tx_dev = &mhu->tx_dev;
+
+ rx_dev->base = mhu->rx_region.base_addr;
+ rx_dev->frame = MHU_V2_X_RECEIVER_FRAME;
+
+ tx_dev->base = mhu->tx_region.base_addr;
+ tx_dev->frame = MHU_V2_X_SENDER_FRAME;
+
+ ret = mhu_v2_x_driver_init(rx_dev, MHU_REV_READ_FROM_HW);
+ if (ret < 0)
+ goto free_mhu;
+
+ ret = mhu_v2_x_driver_init(tx_dev, MHU_REV_READ_FROM_HW);
+ if (ret < 0)
+ goto free_mhu;
+
+ openamp->transport = (void *)mhu;
+
+ return 0;
+
+free_mhu:
+ free(mhu);
+
+ return ret;
+}
+
+int openamp_mhu_deinit(struct openamp_messenger *openamp)
+{
+ struct openamp_mhu *mhu;
+
+ if (!openamp->transport)
+ return 0;
+
+ mhu = openamp->transport;
+ free(mhu);
+
+ openamp->transport = NULL;
+
+ return 0;
+}
diff --git a/components/messaging/openamp/sp/openamp_mhu.h b/components/messaging/openamp/sp/openamp_mhu.h
new file mode 100644
index 000000000..4ba427a6e
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef OPENAMP_MHU_H
+#define OPENAMP_MHU_H
+
+#include <stddef.h>
+#include "openamp_messenger_api.h"
+
+int openamp_mhu_init(struct openamp_messenger *openamp);
+int openamp_mhu_deinit(struct openamp_messenger *openamp);
+
+int openamp_mhu_notify_peer(struct openamp_messenger *openamp);
+int openamp_mhu_receive(struct openamp_messenger *openamp);
+
+#endif
diff --git a/components/messaging/openamp/sp/openamp_virtio.c b/components/messaging/openamp/sp/openamp_virtio.c
new file mode 100644
index 000000000..71d1ceb8c
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_virtio.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <metal/device.h>
+#include <metal/spinlock.h>
+#include <openamp/open_amp.h>
+#include <platform/interface/device_region.h>
+#include <config/interface/config_store.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <trace.h>
+#include "openamp_messenger_api.h"
+
+#define OPENAMP_SHEM_DEVICE_NAME "openamp-virtio"
+#define OPENAMP_RPMSG_ENDPOINT_NAME OPENAMP_SHEM_DEVICE_NAME
+#define OPENAMP_RPMSG_ENDPOINT_ADDR 1024
+
+#define OPENAMP_SHEM_PHYS 0x88000000
+#define OPENAMP_SHEM_PHYS_PAGES 1
+#define OPENAMP_SHEM_SE_PHYS 0xa8000000
+
+#define OPENAMP_SHEM_VDEV_SIZE (4 * 1024)
+#define OPENAMP_SHEM_VRING_SIZE (4 * 1024)
+
+#define OPENAMP_BUFFER_NO_WAIT 0
+#define OPENAMP_BUFFER_WAIT 1
+
+#define VIRTQUEUE_NR 2
+#define VQ_TX 0
+#define VQ_RX 1
+
+#define VRING_DESCRIPTORS 16
+#define VRING_ALIGN 4
+
+#define container_of(ptr, type, member) \
+ ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
+
+struct openamp_virtio_shm {
+ uintptr_t base_addr;
+ size_t size;
+ uintptr_t vdev_status;
+ size_t vdev_status_size;
+ uintptr_t payload_addr;
+ size_t payload_size;
+ uintptr_t vring_tx;
+ size_t vring_tx_size;
+ uintptr_t vring_rx;
+ size_t vring_rx_size;
+
+ metal_phys_addr_t shm_physmap[OPENAMP_SHEM_PHYS_PAGES];
+};
+
+struct openamp_virtio_metal {
+ struct metal_spinlock lock;
+ struct metal_device shm_dev;
+ struct metal_device *io_dev;
+
+ struct metal_io_region *io;
+ struct openamp_virtio_shm shm;
+};
+
+struct openamp_virtio_device {
+ struct virtio_device virtio_dev;
+ struct virtqueue *vq[VIRTQUEUE_NR];
+ struct virtio_vring_info rvrings[VIRTQUEUE_NR];
+};
+
+struct openamp_virtio_rpmsg {
+ struct rpmsg_virtio_device rpmsg_vdev;
+ struct rpmsg_endpoint ep;
+ uint8_t *req_buf;
+ uint32_t req_len;
+ uint8_t *resp_buf;
+ size_t resp_len;
+};
+
+struct openamp_virtio {
+ struct openamp_messenger *openamp;
+ struct openamp_virtio_rpmsg rpmsg;
+ struct openamp_virtio_device vdev;
+ struct openamp_virtio_metal metal;
+};
+
+static struct openamp_virtio *openamp_virtio_from_dev(struct virtio_device *vdev)
+{
+ struct openamp_virtio_device *openamp_vdev;
+
+ openamp_vdev = container_of(vdev, struct openamp_virtio_device,
+ virtio_dev);
+
+ return container_of(openamp_vdev, struct openamp_virtio, vdev);
+}
+
+static struct openamp_virtio_rpmsg *openamp_virtio_rpmsg_from_dev(struct rpmsg_device *rdev)
+{
+ struct rpmsg_virtio_device *rvdev;
+
+ rvdev = container_of(rdev, struct rpmsg_virtio_device, rdev);
+
+ return container_of(rvdev, struct openamp_virtio_rpmsg, rpmsg_vdev);
+
+}
+
+static void openamp_virtio_metal_device_setup(struct metal_device *shm_dev,
+ struct openamp_virtio_shm *shm)
+{
+ struct metal_io_region *shm_region;
+
+ shm_region = &shm_dev->regions[0];
+
+ shm_dev->name = OPENAMP_SHEM_DEVICE_NAME;
+ shm_dev->num_regions = 1;
+
+ shm_region->virt = (void *)shm->payload_addr;
+ shm_region->size = shm->payload_size;
+
+ shm_region->physmap = (metal_phys_addr_t *)&shm->shm_physmap;
+ shm_region->page_shift = (metal_phys_addr_t)(-1);
+ shm_region->page_mask = (metal_phys_addr_t)(-1);
+}
+
+static int openamp_virtio_metal_init(struct openamp_virtio_metal *metal)
+{
+ struct metal_init_params params = METAL_INIT_DEFAULTS;
+ struct metal_device *shm_dev = &metal->shm_dev;
+ int ret;
+
+ openamp_virtio_metal_device_setup(shm_dev, &metal->shm);
+
+ metal_spinlock_init(&metal->lock);
+
+ ret = metal_init(&params);
+ if (ret < 0)
+ return ret;
+
+ ret = metal_register_generic_device(shm_dev);
+ if (ret < 0)
+ goto metal_finish;
+
+ ret = metal_device_open("generic", OPENAMP_SHEM_DEVICE_NAME,
+ &metal->io_dev);
+ if (ret < 0)
+ goto metal_finish;
+
+ metal->io = metal_device_io_region(metal->io_dev, 0);
+ if (!metal->io) {
+ EMSG("openamp: virtio: failed to init metal io");
+ ret = -EPROTO;
+ goto metal_finish;
+ }
+
+ return 0;
+
+metal_finish:
+ metal_finish();
+ return ret;
+}
+
+static unsigned char openamp_virtio_status_get(struct virtio_device *vdev)
+{
+ struct openamp_virtio *virtio = openamp_virtio_from_dev(vdev);
+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
+
+ uint32_t status = *(volatile uint32_t *)shm->vdev_status;
+
+ return status;
+}
+
+static void openamp_virtio_status_set(struct virtio_device *vdev,
+ unsigned char status)
+{
+ struct openamp_virtio *virtio = openamp_virtio_from_dev(vdev);
+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
+
+ *(volatile uint32_t *)shm->vdev_status = status;
+}
+
+static uint32_t openamp_virtio_features_get(struct virtio_device *vdev)
+{
+ return 1 << VIRTIO_RPMSG_F_NS;
+}
+
+static void openamp_virtio_notify(struct virtqueue *vq)
+{
+ struct openamp_virtio_device *openamp_vdev;
+ struct openamp_messenger *openamp;
+ struct openamp_virtio *virtio;
+ int ret;
+
+ openamp_vdev = container_of(vq->vq_dev, struct openamp_virtio_device, virtio_dev);
+ virtio = container_of(openamp_vdev, struct openamp_virtio, vdev);
+ openamp = virtio->openamp;
+
+ ret = openamp->platform_ops->transport_notify(openamp);
+ if (ret < 0)
+ EMSG("openamp: virtio: erro in transport_notify: %d", ret);
+}
+
+const static struct virtio_dispatch openamp_virtio_dispatch = {
+ .get_status = openamp_virtio_status_get,
+ .set_status = openamp_virtio_status_set,
+ .get_features = openamp_virtio_features_get,
+ .notify = openamp_virtio_notify,
+};
+
+static int openamp_virtio_device_setup(struct openamp_virtio *virtio)
+{
+ struct openamp_virtio_metal *metal = &virtio->metal;
+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
+ struct virtio_device *vdev = &openamp_vdev->virtio_dev;
+ struct openamp_virtio_shm *shm = &metal->shm;
+ struct virtio_vring_info *rvring;
+
+ rvring = &openamp_vdev->rvrings[0];
+
+ vdev->role = RPMSG_REMOTE;
+ vdev->vrings_num = VIRTQUEUE_NR;
+ vdev->func = &openamp_virtio_dispatch;
+
+ openamp_vdev->vq[VQ_TX] = virtqueue_allocate(VRING_DESCRIPTORS);
+ if (!openamp_vdev->vq[VQ_TX]) {
+ EMSG("openamp: virtio: failed to allocate virtqueue 0");
+ return -ENOMEM;
+ }
+ rvring->io = metal->io;
+ rvring->info.vaddr = (void *)shm->vring_tx;
+ rvring->info.num_descs = VRING_DESCRIPTORS;
+ rvring->info.align = VRING_ALIGN;
+ rvring->vq = openamp_vdev->vq[VQ_TX];
+
+ openamp_vdev->vq[VQ_RX] = virtqueue_allocate(VRING_DESCRIPTORS);
+ if (!openamp_vdev->vq[VQ_RX]) {
+ EMSG("openamp: virtio: failed to allocate virtqueue 1");
+ goto free_vq;
+ }
+ rvring = &openamp_vdev->rvrings[VQ_RX];
+ rvring->io = metal->io;
+ rvring->info.vaddr = (void *)shm->vring_rx;
+ rvring->info.num_descs = VRING_DESCRIPTORS;
+ rvring->info.align = VRING_ALIGN;
+ rvring->vq = openamp_vdev->vq[VQ_RX];
+
+ vdev->vrings_info = &openamp_vdev->rvrings[0];
+
+ return 0;
+
+free_vq:
+ virtqueue_free(openamp_vdev->vq[VQ_TX]);
+ virtqueue_free(openamp_vdev->vq[VQ_RX]);
+
+ return -ENOMEM;
+}
+
+static int openamp_virtio_rpmsg_endpoint_callback(struct rpmsg_endpoint *ep,
+ void *data, size_t len,
+ uint32_t src, void *priv)
+{
+ struct openamp_virtio_rpmsg *vrpmsg;
+ struct rpmsg_device *rdev;
+
+ rdev = ep->rdev;
+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
+
+ rpmsg_hold_rx_buffer(ep, data);
+ vrpmsg->resp_buf = data;
+ vrpmsg->resp_len = len;
+
+ return 0;
+}
+
+static void openamp_virtio_rpmsg_service_unbind(struct rpmsg_endpoint *ep)
+{
+ struct openamp_virtio_rpmsg *vrpmsg;
+ struct rpmsg_device *rdev;
+
+ rdev = container_of(ep, struct rpmsg_device, ns_ept);
+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
+
+ rpmsg_destroy_ept(&vrpmsg->ep);
+}
+
+static void openamp_virtio_rpmsg_endpoint_bind(struct rpmsg_device *rdev,
+ const char *name,
+ unsigned int dest)
+{
+ struct openamp_virtio_rpmsg *vrpmsg;
+
+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
+
+ rpmsg_create_ept(&vrpmsg->ep, rdev, name, RPMSG_ADDR_ANY, dest,
+ openamp_virtio_rpmsg_endpoint_callback,
+ openamp_virtio_rpmsg_service_unbind);
+}
+
+static int openamp_virtio_rpmsg_device_setup(struct openamp_virtio *virtio,
+ struct device_region *virtio_dev)
+{
+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
+ struct rpmsg_virtio_device *rpmsg_vdev = &vrpmsg->rpmsg_vdev;
+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
+ struct virtio_device *vdev = &openamp_vdev->virtio_dev;
+ struct openamp_virtio_metal *metal = &virtio->metal;
+ int ret;
+
+ /*
+ * we assume here that we are the client side and do not need to
+ * initialize the share memory poll (this is done at server side).
+ */
+ ret = rpmsg_init_vdev(rpmsg_vdev, vdev,
+ openamp_virtio_rpmsg_endpoint_bind, metal->io,
+ NULL);
+ if (ret < 0) {
+ EMSG("openamp: virtio: init vdev failed: %d", ret);
+ return ret;
+ }
+
+
+ ret = rpmsg_create_ept(&vrpmsg->ep, &rpmsg_vdev->rdev,
+ OPENAMP_RPMSG_ENDPOINT_NAME, RPMSG_ADDR_ANY,
+ RPMSG_ADDR_ANY,
+ openamp_virtio_rpmsg_endpoint_callback,
+ openamp_virtio_rpmsg_service_unbind);
+ if (ret < 0) {
+ EMSG("openamp: virtio: failed to create endpoint: %d", ret);
+ return ret;
+ }
+
+ /* set default remote addr */
+ vrpmsg->ep.dest_addr = OPENAMP_RPMSG_ENDPOINT_ADDR;
+
+ return 0;
+}
+
+static void openamp_virtio_shm_set(struct openamp_virtio *virtio,
+ struct device_region *virtio_region)
+{
+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
+
+ shm->base_addr = virtio_region->base_addr;
+ shm->size = virtio_region->io_region_size;
+
+ shm->vdev_status = shm->base_addr;
+ shm->vdev_status_size = OPENAMP_SHEM_VDEV_SIZE;
+
+ shm->vring_rx = shm->base_addr + shm->size -
+ (2 * OPENAMP_SHEM_VRING_SIZE);
+ shm->vring_rx_size = OPENAMP_SHEM_VRING_SIZE;
+
+ shm->vring_tx = shm->vring_rx + shm->vring_rx_size;
+ shm->vring_tx_size = OPENAMP_SHEM_VRING_SIZE;
+
+ shm->payload_addr = shm->vdev_status + shm->vdev_status_size;
+ shm->payload_size = shm->size - shm->vdev_status_size -
+ shm->vring_rx_size - shm->vring_tx_size;
+
+ shm->shm_physmap[0] = OPENAMP_SHEM_PHYS + shm->vdev_status_size;
+
+ IMSG("SHEM: base: 0x%p size: %ld",
+ (void *)shm->base_addr, shm->size);
+ IMSG("VDEV: base: 0x%p size: %ld",
+ (void *)shm->vdev_status, shm->vdev_status_size);
+ IMSG("PAYLOAD: base: 0x%p size: %ld",
+ (void *)shm->payload_addr, shm->payload_size);
+ IMSG("VRING_TX: base: 0x%p size: %ld",
+ (void *)shm->vring_tx, shm->vring_tx_size);
+ IMSG("VRING_RX: base: 0x%p size: %ld",
+ (void *)shm->vring_rx, shm->vring_rx_size);
+ IMSG("PHYMAP: base: 0x%p", (void *)shm->shm_physmap[0]);
+}
+
+static int openamp_virtio_device_get(const char *dev,
+ struct device_region *dev_region)
+{
+ bool found;
+
+ found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
+ dev_region, sizeof(*dev_region));
+ if (!found) {
+ EMSG("openamp: virtio: device region not found: %s", dev);
+ return -EINVAL;
+ }
+
+ if (dev_region->base_addr == 0 || dev_region->io_region_size == 0) {
+ EMSG("openamp: virtio: device region not valid");
+ return -EINVAL;
+ }
+
+ IMSG("openamp: virtio: device region found: %s addr: 0x%p size: %ld",
+ dev, (void *)dev_region->base_addr, dev_region->io_region_size);
+
+ return 0;
+}
+
+int openamp_virtio_call_begin(struct openamp_messenger *openamp, uint8_t **req_buf,
+ size_t req_len)
+{
+ struct openamp_virtio *virtio = openamp->platform;
+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
+ struct rpmsg_endpoint *ep = &vrpmsg->ep;
+
+
+ *req_buf = rpmsg_get_tx_payload_buffer(ep, &vrpmsg->req_len,
+ OPENAMP_BUFFER_WAIT);
+ if (*req_buf == NULL)
+ return -EINVAL;
+
+ if (vrpmsg->req_len < req_len)
+ return -E2BIG;
+
+ vrpmsg->req_buf = *req_buf;
+
+ return 0;
+}
+
+int openamp_virtio_call_invoke(struct openamp_messenger *openamp,
+ uint8_t **resp_buf, size_t *resp_len)
+{
+ const struct openamp_platform_ops *ops = openamp->platform_ops;
+ struct openamp_virtio *virtio = openamp->platform;
+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
+ struct rpmsg_endpoint *ep = &vrpmsg->ep;
+ int ret;
+
+ ret = rpmsg_send_nocopy(ep, vrpmsg->req_buf, vrpmsg->req_len);
+ if (ret < 0) {
+ EMSG("openamp: virtio: send nocopy failed: %d", ret);
+ return -EIO;
+ }
+
+ if (ret != vrpmsg->req_len) {
+ EMSG("openamp: virtio: send less bytes %d than requested %d",
+ ret, vrpmsg->req_len);
+ return -EIO;
+ }
+
+ if (!ops->transport_receive)
+ return 0;
+
+ ret = ops->transport_receive(openamp);
+ if (ret < 0) {
+ EMSG("openamp: virtio: failed transport_receive");
+ return -EIO;
+ }
+
+ virtqueue_notification(openamp_vdev->vq[VQ_RX]);
+
+ *resp_buf = vrpmsg->resp_buf;
+ *resp_len = vrpmsg->resp_len;
+
+ return 0;
+}
+
+void openamp_virtio_call_end(struct openamp_messenger *openamp)
+{
+ struct openamp_virtio *virtio = openamp->platform;
+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
+
+ rpmsg_release_rx_buffer(&vrpmsg->ep, vrpmsg->resp_buf);
+
+ vrpmsg->req_buf = NULL;
+ vrpmsg->req_len = 0;
+ vrpmsg->resp_buf = NULL;
+ vrpmsg->resp_len = 0;
+}
+
+void *openamp_virtio_virt_to_phys(struct openamp_messenger *openamp, void *va)
+{
+ struct openamp_virtio *virtio = openamp->platform;
+ struct openamp_virtio_metal *metal = &virtio->metal;
+
+ return (void *)metal_io_virt_to_phys(metal->io, va);
+}
+
+void *openamp_virtio_phys_to_virt(struct openamp_messenger *openamp, void *pa)
+{
+ struct openamp_virtio *virtio = openamp->platform;
+ struct openamp_virtio_metal *metal = &virtio->metal;
+
+ return metal_io_phys_to_virt(metal->io, (metal_phys_addr_t)pa);
+}
+
+int openamp_virtio_init(struct openamp_messenger *openamp)
+{
+ struct device_region virtio_dev;
+ struct openamp_virtio *virtio;
+ int ret;
+
+ if (openamp->platform)
+ return 0;
+
+
+ virtio = malloc(sizeof(*virtio));
+ if (!virtio)
+ return -ENOMEM;
+
+ virtio->openamp = openamp;
+
+ ret = openamp_virtio_device_get(OPENAMP_SHEM_DEVICE_NAME, &virtio_dev);
+ if (ret < 0)
+ goto free_virtio;
+
+ openamp_virtio_shm_set(virtio, &virtio_dev);
+
+ ret = openamp_virtio_metal_init(&virtio->metal);
+ if (ret < 0)
+ goto free_virtio;
+
+ ret = openamp_virtio_device_setup(virtio);
+ if (ret < 0)
+ goto finish_metal;
+
+ ret = openamp_virtio_rpmsg_device_setup(virtio, &virtio_dev);
+ if (ret < 0) {
+ EMSG("openamp: virtio: rpmsg device setup failed: %d", ret);
+ goto finish_metal;
+ }
+
+ openamp->platform = virtio;
+
+ return 0;
+
+finish_metal:
+ metal_finish();
+
+free_virtio:
+ free(virtio);
+
+ return ret;
+}
+
+int openamp_virtio_deinit(struct openamp_messenger *openamp)
+{
+ struct openamp_virtio *virtio;
+
+ if (!openamp->platform)
+ return 0;
+
+ virtio = openamp->platform;
+
+ metal_finish();
+ free(virtio);
+
+ openamp->platform = NULL;
+
+ return 0;
+}
diff --git a/components/messaging/openamp/sp/openamp_virtio.h b/components/messaging/openamp/sp/openamp_virtio.h
new file mode 100644
index 000000000..bb4f7a514
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_virtio.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef OPENAMP_VIRTIO_H
+#define OPENAMP_VIRTIO_H
+
+#include <stddef.h>
+#include "openamp_messenger_api.h"
+
+int openamp_virtio_call_begin(struct openamp_messenger *openamp,
+ uint8_t **req_buf, size_t req_len);
+int openamp_virtio_call_invoke(struct openamp_messenger *openamp,
+ uint8_t **resp_buf, size_t *resp_len);
+int openamp_virtio_call_end(struct openamp_messenger *openamp);
+void *openamp_virtio_virt_to_phys(struct openamp_messenger *openamp, void *va);
+void *openamp_virtio_phys_to_virt(struct openamp_messenger *openamp, void *pa);
+
+int openamp_virtio_init(struct openamp_messenger *openamp);
+int openamp_virtio_deinit(struct openamp_messenger *openamp);
+
+#endif
diff --git a/components/rpc/common/caller/component.cmake b/components/rpc/common/caller/component.cmake
index 9cb5138fd..0c8934a9b 100644
--- a/components/rpc/common/caller/component.cmake
+++ b/components/rpc/common/caller/component.cmake
@@ -8,6 +8,16 @@ if (NOT DEFINED TGT)
message(FATAL_ERROR "mandatory parameter TGT is not defined.")
endif()
+target_include_directories(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}"
+)
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+ "${CMAKE_CURRENT_LIST_DIR}/rpc_caller_session.h"
+ "${CMAKE_CURRENT_LIST_DIR}/rpc_caller.h"
+ )
+
target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpc_caller_session.c"
"${CMAKE_CURRENT_LIST_DIR}/rpc_caller.c"
)
diff --git a/components/rpc/common/caller/rpc_caller.c b/components/rpc/common/caller/rpc_caller.c
index 2dceabeb8..4af9d8ccc 100644
--- a/components/rpc/common/caller/rpc_caller.c
+++ b/components/rpc/common/caller/rpc_caller.c
@@ -1,39 +1,63 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <rpc_caller.h>
-#include <stdint.h>
-#include <protocols/rpc/common/packed-c/encoding.h>
+#include "rpc_caller.h"
-void rpc_caller_init(struct rpc_caller *s, void *context)
+rpc_status_t rpc_caller_open_session(struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id)
{
- s->context = context;
+ if (!caller)
+ return RPC_ERROR_INVALID_VALUE;
- /* The default encoding scheme - may be overridden by a client */
- s->encoding = TS_RPC_ENCODING_PACKED_C;
+ return caller->open_session(caller->context, service_uuid, endpoint_id);
}
-void rpc_caller_set_encoding_scheme(struct rpc_caller *s, uint32_t encoding)
+rpc_status_t rpc_caller_find_and_open_session(struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid)
{
- s->encoding = encoding;
+ if (!caller)
+ return RPC_ERROR_INVALID_VALUE;
+
+ return caller->find_and_open_session(caller->context, service_uuid);
+}
+
+rpc_status_t rpc_caller_close_session(struct rpc_caller_interface *caller)
+{
+ if (!caller)
+ return RPC_ERROR_INVALID_VALUE;
+
+ return caller->close_session(caller->context);
}
-rpc_call_handle rpc_caller_begin(struct rpc_caller *s,
- uint8_t **req_buf, size_t req_len)
+rpc_status_t rpc_caller_create_shared_memory(struct rpc_caller_interface *caller, size_t length,
+ struct rpc_caller_shared_memory *shared_memory)
{
- return s->call_begin(s->context, req_buf, req_len);
+ if (!caller)
+ return RPC_ERROR_INVALID_VALUE;
+
+ return caller->create_shared_memory(caller->context, length, shared_memory);
}
-rpc_status_t rpc_caller_invoke(struct rpc_caller *s, rpc_call_handle handle,
- uint32_t opcode, rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len)
+rpc_status_t rpc_caller_release_shared_memory(struct rpc_caller_interface *caller,
+ struct rpc_caller_shared_memory *shared_memory)
{
- return s->call_invoke(s->context, handle, opcode, opstatus, resp_buf, resp_len);
+ if (!caller)
+ return RPC_ERROR_INVALID_VALUE;
+
+ return caller->release_shared_memory(caller->context, shared_memory);
}
-void rpc_caller_end(struct rpc_caller *s, rpc_call_handle handle)
+rpc_status_t rpc_caller_call(struct rpc_caller_interface *caller, uint16_t opcode,
+ struct rpc_caller_shared_memory *shared_memory, size_t request_length,
+ size_t *response_length, service_status_t *service_status)
{
- s->call_end(s->context, handle);
+ if (!caller)
+ return RPC_ERROR_INVALID_VALUE;
+
+ return caller->call(caller->context, opcode, shared_memory, request_length,
+ response_length, service_status);
}
diff --git a/components/rpc/common/caller/rpc_caller.h b/components/rpc/common/caller/rpc_caller.h
new file mode 100644
index 000000000..9581fd0cb
--- /dev/null
+++ b/components/rpc/common/caller/rpc_caller.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPC_CALLER_H
+#define RPC_CALLER_H
+
+#include "rpc_status.h"
+#include "rpc_uuid.h"
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * The rpc_caller public interface may be exported as a public interface to
+ * a shared library.
+ */
+#ifdef EXPORT_PUBLIC_INTERFACE_RPC_CALLER
+#define RPC_CALLER_EXPORTED __attribute__((__visibility__("default")))
+#else
+#define RPC_CALLER_EXPORTED
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Shared memory descriptor of an RPC caller
+ *
+ */
+struct rpc_caller_shared_memory {
+ uint64_t id; /** Implementation defined ID of the shared memory */
+ void *buffer; /** Address of the shared memory (virtual) */
+ size_t size; /** Size of the shared memory */
+};
+
+struct rpc_caller_interface {
+ void *context;
+
+ rpc_status_t (*open_session)(void *context, const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id);
+ rpc_status_t (*find_and_open_session)(void *context, const struct rpc_uuid *service_uuid);
+ rpc_status_t (*close_session)(void *context);
+
+ rpc_status_t (*create_shared_memory)(void *context, size_t size,
+ struct rpc_caller_shared_memory *shared_memory);
+ rpc_status_t (*release_shared_memory)(void *context,
+ struct rpc_caller_shared_memory *shared_memory);
+
+ rpc_status_t (*call)(void *context, uint16_t opcode,
+ struct rpc_caller_shared_memory *shared_memory, size_t request_length,
+ size_t *response_length, service_status_t *service_status);
+};
+
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_open_session(struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id);
+
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_find_and_open_session(struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid);
+
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_close_session(struct rpc_caller_interface *caller);
+
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_create_shared_memory(struct rpc_caller_interface *caller, size_t size,
+ struct rpc_caller_shared_memory *shared_memory);
+
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_release_shared_memory(struct rpc_caller_interface *caller,
+ struct rpc_caller_shared_memory *shared_memory);
+
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_call(struct rpc_caller_interface *caller, uint16_t opcode,
+ struct rpc_caller_shared_memory *shared_memory, size_t request_length,
+ size_t *response_length, service_status_t *service_status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPC_CALLER_H */
diff --git a/components/rpc/common/caller/rpc_caller_session.c b/components/rpc/common/caller/rpc_caller_session.c
new file mode 100644
index 000000000..d72a31815
--- /dev/null
+++ b/components/rpc/common/caller/rpc_caller_session.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpc_caller_session.h"
+#include "util.h"
+#include <string.h>
+
+static rpc_status_t initalize_shared_memory(struct rpc_caller_session *session,
+ struct rpc_caller_interface *caller,
+ size_t shared_memory_size)
+{
+ if (shared_memory_size) {
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ status = rpc_caller_create_shared_memory(caller, shared_memory_size,
+ &session->shared_memory);
+ if (status) {
+ rpc_caller_close_session(caller);
+ return status;
+ }
+
+ session->shared_memory_policy = alloc_for_session;
+ } else {
+ session->shared_memory = (struct rpc_caller_shared_memory){ 0 };
+ session->shared_memory_policy = alloc_for_each_call;
+ }
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t rpc_caller_session_open(struct rpc_caller_session *session,
+ struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id,
+ size_t shared_memory_size)
+{
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!session || !caller || !service_uuid)
+ return RPC_ERROR_INVALID_VALUE;
+
+ status = rpc_caller_open_session(caller, service_uuid, endpoint_id);
+ if (status)
+ return status;
+
+ status = initalize_shared_memory(session, caller, shared_memory_size);
+ if (status)
+ return status;
+
+ session->caller = caller;
+ session->is_call_transaction_in_progress = false;
+ session->request_length = 0;
+
+ return status;
+}
+
+rpc_status_t rpc_caller_session_find_and_open(struct rpc_caller_session *session,
+ struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid,
+ size_t shared_memory_size)
+{
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!session || !caller || !service_uuid)
+ return RPC_ERROR_INVALID_VALUE;
+
+ status = rpc_caller_find_and_open_session(caller, service_uuid);
+ if (status)
+ return status;
+
+ status = initalize_shared_memory(session, caller, shared_memory_size);
+ if (status)
+ return status;
+
+ session->caller = caller;
+ session->is_call_transaction_in_progress = false;
+ session->request_length = 0;
+
+ return status;
+}
+
+rpc_status_t rpc_caller_session_close(struct rpc_caller_session *session)
+{
+ if (!session)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (session->is_call_transaction_in_progress)
+ return RPC_ERROR_INVALID_STATE;
+
+ if (session->shared_memory_policy == alloc_for_session) {
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ rpc_status = rpc_caller_release_shared_memory(session->caller,
+ &session->shared_memory);
+ if (rpc_status != RPC_SUCCESS)
+ return rpc_status;
+ }
+
+ return rpc_caller_close_session(session->caller);
+}
+
+rpc_call_handle rpc_caller_session_begin(struct rpc_caller_session *session,
+ uint8_t **request_buffer, size_t request_length,
+ size_t response_max_length)
+{
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+ size_t required_buffer_length = MAX(request_length, response_max_length);
+
+ if (required_buffer_length > UINT32_MAX)
+ return NULL;
+
+ if (!session || !request_buffer || session->is_call_transaction_in_progress)
+ return NULL;
+
+ switch (session->shared_memory_policy) {
+ case alloc_for_each_call:
+ if (session->shared_memory.buffer || session->shared_memory.size)
+ return NULL; /* There's already a shared memory */
+
+ status = rpc_caller_create_shared_memory(session->caller, required_buffer_length,
+ &session->shared_memory);
+ if (status)
+ return NULL; /* Failed to create shared memory */
+ break;
+
+ case alloc_for_session:
+ if (!session->shared_memory.buffer || !session->shared_memory.size)
+ return NULL; /* There's no shared memory */
+
+ if (session->shared_memory.size < required_buffer_length)
+ return NULL; /* The allocated shared memory is too small */
+ break;
+
+ default:
+ /* Invalid shared memory policy */
+ return NULL;
+ }
+
+ *request_buffer = session->shared_memory.buffer;
+
+ session->is_call_transaction_in_progress = true;
+ session->request_length = request_length;
+
+ return (rpc_call_handle)session;
+}
+
+rpc_status_t rpc_caller_session_invoke(rpc_call_handle handle, uint32_t opcode,
+ uint8_t **response_buffer, size_t *response_length,
+ service_status_t *service_status)
+{
+ struct rpc_caller_session *session = (struct rpc_caller_session *)handle;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!handle || !response_buffer || !response_length)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (!session->is_call_transaction_in_progress)
+ return RPC_ERROR_INVALID_STATE;
+
+ if (session->request_length &&
+ (!session->shared_memory.buffer || !session->shared_memory.size))
+ return RPC_ERROR_INVALID_STATE;
+
+ status = rpc_caller_call(session->caller, opcode, &session->shared_memory,
+ session->request_length, response_length, service_status);
+ if (status || *response_length > session->shared_memory.size) {
+ *response_buffer = NULL;
+ *response_length = 0;
+ return status;
+ }
+
+ *response_buffer = session->shared_memory.buffer;
+
+ return status;
+}
+
+rpc_status_t rpc_caller_session_end(rpc_call_handle handle)
+{
+ struct rpc_caller_session *session = (struct rpc_caller_session *)handle;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!handle)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (!session->is_call_transaction_in_progress)
+ return RPC_ERROR_INVALID_STATE;
+
+ if (session->request_length &&
+ (!session->shared_memory.buffer || !session->shared_memory.size))
+ return RPC_ERROR_INVALID_STATE; /* There's no shared memory */
+
+ switch (session->shared_memory_policy) {
+ case alloc_for_each_call:
+ status = rpc_caller_release_shared_memory(session->caller,
+ &session->shared_memory);
+ if (status)
+ return status; /* Failed to release shared memory */
+
+ session->shared_memory = (struct rpc_caller_shared_memory){ 0 };
+ break;
+
+ case alloc_for_session:
+ /* Nothing to do */
+ break;
+
+ default:
+ return RPC_ERROR_INVALID_STATE;
+ }
+
+ session->is_call_transaction_in_progress = false;
+ session->request_length = 0;
+
+ return RPC_SUCCESS;
+}
diff --git a/components/rpc/common/caller/rpc_caller_session.h b/components/rpc/common/caller/rpc_caller_session.h
new file mode 100644
index 000000000..debcf19cf
--- /dev/null
+++ b/components/rpc/common/caller/rpc_caller_session.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPC_CALLER_SESSION_H
+#define RPC_CALLER_SESSION_H
+
+#include "rpc_caller.h"
+#include "rpc_status.h"
+#include "rpc_uuid.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *rpc_call_handle;
+
+enum rpc_caller_memory_policy {
+ alloc_for_each_call = 0,
+ alloc_for_session,
+};
+
+/**
+ * @brief RPC caller session
+ *
+ * Builds a session on top of the rpc_caller_interface. It provides high level functions for service
+ * caller implementations and for prior service discovery.
+ */
+struct rpc_caller_session {
+ /** Caller interface */
+ struct rpc_caller_interface *caller;
+
+ /** Shared memory instance for the exchanging of RPC request and response parameters. */
+ struct rpc_caller_shared_memory shared_memory;
+
+ /** Controls how and when the shared memory is allocated for the RPC calls. */
+ enum rpc_caller_memory_policy shared_memory_policy;
+
+ /**
+ * Indicates if a call transaction has been started by the begin function but was not
+ * finished yet (i.e. end was not called).
+ */
+ bool is_call_transaction_in_progress;
+
+ /**
+ * Stores the request length of the current transaction. Its value is set by the begin
+ * function and then used in the invoke step.
+ */
+ size_t request_length;
+};
+
+/**
+ * @brief
+ *
+ * @param session
+ * @param caller
+ * @param service_uuid
+ * @param endpoint_id
+ * @param shared_memory_size
+ * @return RPC_CALLER_EXPORTED
+ */
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_session_open(struct rpc_caller_session *session,
+ struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id,
+ size_t shared_memory_size);
+
+/**
+ * @brief
+ *
+ * @param session
+ * @param caller
+ * @param service_uuid
+ * @param shared_memory_size
+ * @return RPC_CALLER_EXPORTED
+ */
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_session_find_and_open(struct rpc_caller_session *session,
+ struct rpc_caller_interface *caller,
+ const struct rpc_uuid *service_uuid,
+ size_t shared_memory_size);
+
+/**
+ * @brief Closes the RPC caller session
+ *
+ * @param session Caller session instance
+ * @return RPC_CALLER_EXPORTED
+ */
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_session_close(struct rpc_caller_session *session);
+
+/**
+ * @brief Begins an RPC call
+ *
+ * The function returns a buffer where the service caller can build the request.
+ *
+ * @param session Caller session instance
+ * @param request_buffer Pointer of the request buffer
+ * @param request_length Request length
+ * @param response_max_length Expected maximal length of the response
+ * @return rpc_call_handle Handle of the started call
+ */
+RPC_CALLER_EXPORTED
+rpc_call_handle rpc_caller_session_begin(struct rpc_caller_session *session,
+ uint8_t **request_buffer,
+ size_t request_length,
+ size_t response_max_length);
+
+/**
+ * @brief Invoke phase of the RPC call
+ *
+ * Invokes the call on the remote side and returns the response buffer and service status. The
+ * service caller can parse the response from the response buffer.
+ * After this call the request buffer is not available for the service caller.
+ *
+ * @param handle RPC call handle
+ * @param opcode The opcode of the remote function
+ * @param response_buffer Pointer of the response buffer
+ * @param response_length Length of the response buffer
+ * @param service_status Service specific status code
+ * @return RPC_CALLER_EXPORTED
+ */
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_session_invoke(rpc_call_handle handle, uint32_t opcode,
+ uint8_t **response_buffer,
+ size_t *response_length,
+ service_status_t *service_status);
+
+/**
+ * @brief Ends the RPC call
+ *
+ * Indicates if the response has been parsed by the service calls and the RPC session can free the
+ * response buffer.
+ *
+ * @param handle RPC call handle
+ * @return RPC_CALLER_EXPORTED
+ */
+RPC_CALLER_EXPORTED
+rpc_status_t rpc_caller_session_end(rpc_call_handle handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPC_CALLER_SESSION_H */
diff --git a/components/rpc/common/demux/rpc_demux.c b/components/rpc/common/demux/rpc_demux.c
deleted file mode 100644
index 3460396c8..000000000
--- a/components/rpc/common/demux/rpc_demux.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include "rpc_demux.h"
-
-static rpc_status_t receive(struct rpc_interface *rpc_iface, struct call_req *req)
-{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERFACE_DOES_NOT_EXIST;
- struct rpc_demux *context = (struct rpc_demux*)rpc_iface->context;
-
- unsigned int iface_id = call_req_get_interface_id(req);
-
- if (iface_id < RPC_DEMUX_MAX_OUTPUTS) {
-
- rpc_status = rpc_interface_receive(context->outputs[iface_id], req);
- }
-
- return rpc_status;
-}
-
-struct rpc_interface *rpc_demux_init(struct rpc_demux *context)
-{
- context->input.receive = receive;
- context->input.context = context;
-
- for (unsigned int i = 0; i < RPC_DEMUX_MAX_OUTPUTS; ++i) {
-
- context->outputs[i] = NULL;
- }
-
- return &context->input;
-}
-
-void rpc_demux_deinit(struct rpc_demux *context)
-{
- (void)context;
-}
-
-void rpc_demux_attach(struct rpc_demux *context,
- unsigned int iface_id, struct rpc_interface *output)
-{
- assert(iface_id < RPC_DEMUX_MAX_OUTPUTS);
- context->outputs[iface_id] = output;
-}
-
-void rpc_demux_dettach(struct rpc_demux *context,
- unsigned int iface_id)
-{
- assert(iface_id < RPC_DEMUX_MAX_OUTPUTS);
- context->outputs[iface_id] = NULL;
-}
diff --git a/components/rpc/common/demux/rpc_demux.h b/components/rpc/common/demux/rpc_demux.h
deleted file mode 100644
index 46d7b0fb7..000000000
--- a/components/rpc/common/demux/rpc_demux.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef RPC_DEMUX_H
-#define RPC_DEMUX_H
-
-#include <rpc/common/endpoint/rpc_interface.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The default maximum number of output interfaces. May be
- * overridden to meet needs of deployment if necessary.
- */
-#ifndef RPC_DEMUX_MAX_OUTPUTS
-#define RPC_DEMUX_MAX_OUTPUTS (8)
-#endif
-
-/** \brief RPC demux
- *
- * An rpc_demux is an rpc_interface that demultiplexes incoming call requests
- * to 1..* output interfaces. Use an rpc_demux when multiple service
- * providers are co-located and associated with a single RPC endpoint.
- */
-struct rpc_demux
-{
- struct rpc_interface input;
- struct rpc_interface *outputs[RPC_DEMUX_MAX_OUTPUTS];
-};
-
-/**
- * \brief Initialize an rpc_demux
- *
- * After initialization, the required number of output interfaces need
- * to be attached,
- *
- * \param[in] context The instance to initialize
- *
- * \return The input rpc_interface
- */
-struct rpc_interface *rpc_demux_init(struct rpc_demux *context);
-
-/**
- * \brief Cleans up when the instance is no longer needed
- *
- * \param[in] context The instance to de-initialize
- */
-void rpc_demux_deinit(struct rpc_demux *context);
-
-/**
- * \brief Attach an output interface
- *
- * \param[in] context The rpc_demux instance
- * \param[in] iface_id The interface id (small integer)
- * \param[in] output The interface to attach
- */
-void rpc_demux_attach(struct rpc_demux *context,
- unsigned int iface_id, struct rpc_interface *output);
-
-/**
- * \brief Dettach an output interface
- *
- * \param[in] context The rpc_demux instance
- * \param[in] iface_id The interface id (small integer)
- */
-void rpc_demux_dettach(struct rpc_demux *context,
- unsigned int iface_id);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* RPC_DEMUX_H */
diff --git a/components/rpc/ffarpc/endpoint/component.cmake b/components/rpc/common/endpoint/component.cmake
index 9e43ac553..7d8302886 100644
--- a/components/rpc/ffarpc/endpoint/component.cmake
+++ b/components/rpc/common/endpoint/component.cmake
@@ -9,6 +9,6 @@ if (NOT DEFINED TGT)
endif()
target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/ffarpc_call_ep.c"
+ "${CMAKE_CURRENT_LIST_DIR}/rpc_service_interface.c"
)
diff --git a/components/rpc/common/endpoint/rpc_interface.h b/components/rpc/common/endpoint/rpc_interface.h
deleted file mode 100644
index eb985870f..000000000
--- a/components/rpc/common/endpoint/rpc_interface.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef RPC_INTERFACE_H
-#define RPC_INTERFACE_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include <rpc_status.h>
-#include <protocols/rpc/common/packed-c/status.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Definitions related to an rpc call endpoint */
-
-/** \brief Call parameter buffer
- *
- * Describes a buffer for holding call request and response parameters.
- */
-struct call_param_buf {
- size_t size;
- size_t data_len;
- void *data;
-};
-
-static inline struct call_param_buf call_param_buf_init_empty(void *data, size_t size)
-{
- struct call_param_buf v;
-
- v.size = size;
- v.data_len = 0;
- v.data = data;
-
- return v;
-}
-
-static inline struct call_param_buf call_param_buf_init_full(void *data,
- size_t size,
- size_t data_len)
-{
- struct call_param_buf v;
-
- v.size = size;
- v.data_len = data_len;
- v.data = data;
-
- return v;
-}
-
-/** \brief Call request
- *
- * A call request object represents a request from a client that will
- * be handled by a call endpoint.
- */
-struct call_req {
- uint32_t caller_id;
- uint32_t interface_id;
- uint32_t opcode;
- uint32_t encoding;
- rpc_opstatus_t opstatus;
- struct call_param_buf req_buf;
- struct call_param_buf resp_buf;
-};
-
-static inline uint32_t call_req_get_caller_id(const struct call_req *req)
-{
- return req->caller_id;
-}
-
-static inline uint32_t call_req_get_interface_id(const struct call_req *req)
-{
- return req->interface_id;
-}
-
-static inline uint32_t call_req_get_opcode(const struct call_req *req)
-{
- return req->opcode;
-}
-
-static inline uint32_t call_req_get_encoding(const struct call_req *req)
-{
- return req->encoding;
-}
-
-static inline rpc_opstatus_t call_req_get_opstatus(const struct call_req *req)
-{
- return req->opstatus;
-}
-
-static inline void call_req_set_opstatus(struct call_req *req, rpc_opstatus_t opstatus)
-{
- req->opstatus = opstatus;
-}
-
-static inline struct call_param_buf *call_req_get_req_buf(struct call_req *req)
-{
- return &req->req_buf;
-}
-
-static inline struct call_param_buf *call_req_get_resp_buf(struct call_req *req)
-{
- return &req->resp_buf;
-}
-
-/** \brief RPC interface
- *
- * A generalized RPC interface. Provides a standard interface for a
- * call endpoint that handles incoming call requests.
- */
-struct rpc_interface
-{
- void *context;
- rpc_status_t (*receive)(struct rpc_interface *iface, struct call_req *req);
-};
-
-static inline rpc_status_t rpc_interface_receive(struct rpc_interface *iface,
- struct call_req *req)
-{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERFACE_DOES_NOT_EXIST;
-
- if (iface) {
-
- rpc_status = iface->receive(iface, req);
- }
-
- return rpc_status;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* RPC_INTERFACE_H */
diff --git a/components/rpc/common/endpoint/rpc_service_interface.c b/components/rpc/common/endpoint/rpc_service_interface.c
new file mode 100644
index 000000000..67eeb2e3c
--- /dev/null
+++ b/components/rpc/common/endpoint/rpc_service_interface.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpc_service_interface.h"
+
+rpc_status_t rpc_service_receive(struct rpc_service_interface *service,
+ struct rpc_request *request)
+{
+ if (!service)
+ return RPC_ERROR_INVALID_VALUE;
+
+ return service->receive(service->context, request);
+}
diff --git a/components/rpc/common/endpoint/rpc_service_interface.h b/components/rpc/common/endpoint/rpc_service_interface.h
new file mode 100644
index 000000000..3fdfed2f3
--- /dev/null
+++ b/components/rpc/common/endpoint/rpc_service_interface.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPC_INTERFACE_H
+#define RPC_INTERFACE_H
+
+#include "rpc_status.h"
+#include "rpc_uuid.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef EXPORT_PUBLIC_INTERFACE_RPC_SERVICE
+#define RPC_SERVICE_EXPORTED __attribute__((__visibility__("default")))
+#else
+#define RPC_SERVICE_EXPORTED
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief RPC buffer
+ *
+ * Describes an RPC buffer by its data pointer, size and the used data length.
+ */
+struct rpc_buffer {
+ uint8_t *data;
+ size_t data_length;
+ size_t size;
+};
+
+/**
+ * @brief RPC request
+ *
+ * The service should select the requested function by the opcode field. The call's request and
+ * response parameter buffer is accessible via the request and response rpc_buffers. The response's
+ * size must be indicated by the service through setting the data_length field of the response.
+ * The services can identify the caller via the source_id and client_id fields.
+ */
+struct rpc_request {
+ uint16_t source_id; /** Call source ID (i.e. FF-A source ID) */
+ uint8_t interface_id; /** Service interface ID */
+ uint16_t opcode; /** Opcode of the required function */
+ uint32_t client_id; /** Client ID for further caller identification */
+ service_status_t service_status; /** Service specific status code */
+ struct rpc_buffer request; /** Request buffer */
+ struct rpc_buffer response; /** Response buffer */
+};
+
+/**
+ * @brief RPC service interface
+ *
+ * An endpoint (i.e. secure partition) can implement multiple services which are identified by their
+ * service UUID. Once an endpoint receives an RPC call, it selects the matching
+ * rpc_service_interface instance, builds the rpc_request structure and calls the interface's
+ * receive function.
+ * If the service is not able to parse the request (invalid opcode, request or response buffer)
+ * it should return an rpc_status_t value indicating the issue with the RPC request. Otherwise it
+ * must return RPC_SUCCESS.
+ * Service level status codes should be passed in a service specific way.
+ */
+struct rpc_service_interface {
+ void *context;
+ struct rpc_uuid uuid;
+
+ rpc_status_t (*receive)(void *context, struct rpc_request *request);
+};
+
+/**
+ * @brief Call the receive function of the RPC interface.
+ *
+ * @param service The service instance
+ * @param request RPC request
+ * @return rpc_status_t
+ */
+RPC_SERVICE_EXPORTED
+rpc_status_t rpc_service_receive(struct rpc_service_interface *service,
+ struct rpc_request *request);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPC_INTERFACE_H */
diff --git a/components/rpc/common/interface/component.cmake b/components/rpc/common/interface/component.cmake
index d56760222..ae219d611 100644
--- a/components/rpc/common/interface/component.cmake
+++ b/components/rpc/common/interface/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,11 +8,15 @@ if (NOT DEFINED TGT)
message(FATAL_ERROR "mandatory parameter TGT is not defined.")
endif()
-set_property(TARGET ${TGT} PROPERTY RPC_CALLER_PUBLIC_HEADER_FILES
- "${CMAKE_CURRENT_LIST_DIR}/rpc_caller.h"
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
"${CMAKE_CURRENT_LIST_DIR}/rpc_status.h"
+ "${CMAKE_CURRENT_LIST_DIR}/rpc_uuid.h"
)
target_include_directories(${TGT} PUBLIC
- "${CMAKE_CURRENT_LIST_DIR}"
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>"
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpc_uuid.c"
)
diff --git a/components/rpc/common/interface/rpc_caller.h b/components/rpc/common/interface/rpc_caller.h
deleted file mode 100644
index 387489cdb..000000000
--- a/components/rpc/common/interface/rpc_caller.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef RPC_CALLER_H
-#define RPC_CALLER_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include "rpc_status.h"
-
-/*
- * The rpc_caller puplic interface may be exported as a public interface to
- * a shared library.
- */
-#ifdef EXPORT_PUBLIC_INTERFACE_RPC_CALLER
-#define RPC_CALLER_EXPORTED __attribute__((__visibility__("default")))
-#else
-#define RPC_CALLER_EXPORTED
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Defines an abstract interface for calling operations provided by an rpc endpoint.
- * Concrete specializations will map the an RPC or direct calling mechanism to
- * suite the deployment.
- */
-
-typedef void *rpc_call_handle;
-
-struct rpc_caller
-{
- void *context;
- uint32_t encoding;
-
- /* A concrete rpc_caller implements these methods */
- rpc_call_handle (*call_begin)(void *context, uint8_t **req_buf, size_t req_len);
-
- rpc_status_t (*call_invoke)(void *context, rpc_call_handle handle, uint32_t opcode,
- rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len);
-
- void (*call_end)(void *context, rpc_call_handle handle);
-};
-
-/*
- * Called by a concrete rpc_caller to initialise the base rpc_caller.
- */
-void rpc_caller_init(struct rpc_caller *s, void *context);
-
-/*
- * Allows a client to specify the parameter encoding scheme that the client
- * intends to use during an RPC session. It is the client's responsiblity
- * to choose an encoding scheme that is supported by the remote interface.
- */
-RPC_CALLER_EXPORTED void rpc_caller_set_encoding_scheme(struct rpc_caller *s,
- uint32_t encoding);
-
-/*
- * Starts a call transaction. The returned handle is an identifier for the
- * transaction and must be passed as a parameter to call_invoke() and
- * call_end(). A concrete rpc_caller may perform resource allocation during
- * this call. This will include a buffer for the request message parameters.
- * Returns a NULL handle on failure.
- */
-RPC_CALLER_EXPORTED rpc_call_handle rpc_caller_begin(struct rpc_caller *s,
- uint8_t **req_buf, size_t req_len);
-
-/*
- * Invokes the operation identified by the opcode. This method blocks
- * until the operation completes. The status of the call is returned. An
- * additional endpoint specific status value is also returned. If a response
- * message was received, the concrete rpc_caller will have allocated a
- * buffer for the reponse. This buffer will hold valid data until the point when
- * call_end() is called for the transaction.
- */
-RPC_CALLER_EXPORTED rpc_status_t rpc_caller_invoke(struct rpc_caller *s, rpc_call_handle handle,
- uint32_t opcode, rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len);
-
-/*
- * Ends the call transaction, allowing any resource associated with the
- * transaction to be freed.
- */
-RPC_CALLER_EXPORTED void rpc_caller_end(struct rpc_caller *s, rpc_call_handle handle);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* RPC_CALLER_H */
diff --git a/components/rpc/common/interface/rpc_status.h b/components/rpc/common/interface/rpc_status.h
index cba9dacc6..5cd25907a 100644
--- a/components/rpc/common/interface/rpc_status.h
+++ b/components/rpc/common/interface/rpc_status.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,22 +13,24 @@
extern "C" {
#endif
-/** \brief RPC status code type
- *
- * Used for returning the status of an RPC transaction. This is
- * different from the opstatus which is used to return an endpoint
- * specific status value.
+/**
+ * Used for returning the status of an RPC transaction. These values indicating the result of the
+ * RPC layer operations. Service level result must be handled in a service specific way.
*/
+
typedef int32_t rpc_status_t;
-/** \brief RPC operation status code type
- *
- * Used for returning the endpoint specific operation status.
- * Different service layer protocols will use different status
- * value schemes. Status values returned by an operation are
- * carried by the RPC layer using this type.
- */
-typedef int64_t rpc_opstatus_t;
+#define RPC_SUCCESS (0)
+#define RPC_ERROR_INTERNAL (-1)
+#define RPC_ERROR_INVALID_VALUE (-2)
+#define RPC_ERROR_NOT_FOUND (-3)
+#define RPC_ERROR_INVALID_STATE (-4)
+#define RPC_ERROR_TRANSPORT_LAYER (-5)
+#define RPC_ERROR_INVALID_REQUEST_BODY (-6)
+#define RPC_ERROR_INVALID_RESPONSE_BODY (-7)
+#define RPC_ERROR_RESOURCE_FAILURE (-8)
+
+typedef int64_t service_status_t;
#ifdef __cplusplus
}
diff --git a/components/rpc/common/interface/rpc_uuid.c b/components/rpc/common/interface/rpc_uuid.c
new file mode 100644
index 000000000..fd88b6e76
--- /dev/null
+++ b/components/rpc/common/interface/rpc_uuid.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpc_uuid.h"
+#include <string.h>
+
+bool rpc_uuid_equal(const struct rpc_uuid *uuid_a, const struct rpc_uuid *uuid_b)
+{
+ return memcmp(uuid_a->uuid, uuid_b->uuid, sizeof(uuid_a->uuid)) == 0;
+}
diff --git a/components/rpc/common/interface/rpc_uuid.h b/components/rpc/common/interface/rpc_uuid.h
new file mode 100644
index 000000000..52782c742
--- /dev/null
+++ b/components/rpc/common/interface/rpc_uuid.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPC_UUID_H
+#define RPC_UUID_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief RPC UUID
+ *
+ * Describes a UUID for identifying an RPC service.
+ */
+struct rpc_uuid {
+ uint8_t uuid[16];
+};
+
+/**
+ * @brief Checks if two RPC UUIDs are equal
+ *
+ * @param uuid_a UUID A
+ * @param uuid_b UUID B
+ * @return true
+ * @return false
+ */
+bool rpc_uuid_equal(const struct rpc_uuid *uuid_a, const struct rpc_uuid *uuid_b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPC_UUID_H */
diff --git a/components/rpc/common/logging/logging_caller.c b/components/rpc/common/logging/logging_caller.c
index 07c33de5d..f246ebfc1 100644
--- a/components/rpc/common/logging/logging_caller.c
+++ b/components/rpc/common/logging/logging_caller.c
@@ -87,7 +87,7 @@ static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t
if (status == TS_RPC_CALL_ACCEPTED) {
- fprintf(this_instance->log_file, "op_status: %d\n", *opstatus);
+ fprintf(this_instance->log_file, "op_status: %ld\n", *opstatus);
fprintf(this_instance->log_file, "resp_len: %ld\n", *resp_len);
}
diff --git a/components/rpc/common/test/call_param_buf_comparator.h b/components/rpc/common/test/call_param_buf_comparator.h
deleted file mode 100644
index 6bfa72771..000000000
--- a/components/rpc/common/test/call_param_buf_comparator.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#ifndef CALL_PARAM_BUF_COMPARATOR_H_
-#define CALL_PARAM_BUF_COMPARATOR_H_
-
-#include <CppUTestExt/MockSupport.h>
-#include "../endpoint/rpc_interface.h"
-
-class call_param_buf_comparator : public MockNamedValueComparator
-{
-public:
- enum check_mode {
- mode_normal = 0,
- mode_ignore_data_len
- };
-
- call_param_buf_comparator(check_mode mode = mode_normal) : mode(mode)
- {
- }
-
- virtual bool isEqual(const void *object1, const void *object2)
- {
- struct call_param_buf *buf1 = (struct call_param_buf *)object1;
- struct call_param_buf *buf2 = (struct call_param_buf *)object2;
-
- return (buf1->size == buf2->size) &&
- (mode == mode_ignore_data_len || (buf1->data_len == buf2->data_len)) &&
- (buf1->data == buf2->data);
- }
-
- // LCOV_EXCL_START
- virtual SimpleString valueToString(const void *object)
- {
- struct call_param_buf *buf = (struct call_param_buf *)object;
-
- return StringFromFormat("<size = %zu, data_len = %zu%s, data = %p>",
- buf->size, buf->data_len,
- (mode == mode_ignore_data_len) ? " (ignored)" : "",
- buf->data);
- }
- // LCOV_EXCL_STOP
-
-private:
- check_mode mode;
-};
-
-#endif /* CALL_PARAM_BUF_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/call_req_comparator.h b/components/rpc/common/test/call_req_comparator.h
deleted file mode 100644
index 753bab241..000000000
--- a/components/rpc/common/test/call_req_comparator.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#ifndef CALL_REQ_COMPARATOR_H_
-#define CALL_REQ_COMPARATOR_H_
-
-#include <CppUTestExt/MockSupport.h>
-#include <inttypes.h>
-#include "call_param_buf_comparator.h"
-
-class call_req_comparator : public MockNamedValueComparator
-{
-public:
- enum check_mode {
- mode_normal = 0,
- mode_ignore_opstatus
- };
-
- call_req_comparator(check_mode mode) : mode(mode)
- {
- }
-
- virtual bool isEqual(const void *object1, const void *object2)
- {
- struct call_req *req1 = (struct call_req *)object1;
- struct call_req *req2 = (struct call_req *)object2;
- call_param_buf_comparator buf_comparator_normal;
- call_param_buf_comparator buf_comparator_ignore_data_len(
- call_param_buf_comparator::mode_ignore_data_len);
-
- return (req1->caller_id == req2->caller_id) &&
- (req1->interface_id == req2->interface_id) &&
- (req1->opcode == req2->opcode) &&
- (req1->encoding == req2->encoding) &&
- (mode == mode_ignore_opstatus || req1->opstatus == req2->opstatus) &&
- buf_comparator_normal.isEqual(&req1->req_buf, &req2->req_buf) &&
- buf_comparator_ignore_data_len.isEqual(&req1->resp_buf, &req2->resp_buf);
- }
-
- // LCOV_EXCL_START
- virtual SimpleString valueToString(const void *object)
- {
- struct call_req *req = (struct call_req *)object;
- call_param_buf_comparator buf_comparator_normal;
- call_param_buf_comparator buf_comparator_ignore_data_len(
- call_param_buf_comparator::mode_ignore_data_len);
- SimpleString req_buf_str = buf_comparator_normal.valueToString(&req->req_buf);
- SimpleString resp_buf_str =
- buf_comparator_ignore_data_len.valueToString(&req->resp_buf);
-
- return StringFromFormat("caller_id = 0x%" PRIx32 ", interface_id = %" PRIu32 ", " \
- "opcode = %" PRIu32 ", encoding = %" PRIu32 ", " \
- "opstatus = 0x%" PRIx64 "%s, req_buf = %s, " \
- "resp_buf = %s",
- req->caller_id, req->interface_id, req->opcode,
- req->encoding, req->opstatus,
- (mode == mode_ignore_opstatus) ? " (ignore)" : "",
- req_buf_str.asCharString(), resp_buf_str.asCharString());
- }
- // LCOV_EXCL_STOP
-
-private:
- check_mode mode;
-};
-
-#endif /* CALL_REQ_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/component.cmake b/components/rpc/common/test/component.cmake
new file mode 100644
index 000000000..0fed1521c
--- /dev/null
+++ b/components/rpc/common/test/component.cmake
@@ -0,0 +1,18 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/mock_rpc_interface.cpp"
+ )
+
+target_include_directories(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}"
+ )
+
diff --git a/components/rpc/common/test/mock_rpc_interface.cpp b/components/rpc/common/test/mock_rpc_interface.cpp
index af3836d9e..cf4a00564 100644
--- a/components/rpc/common/test/mock_rpc_interface.cpp
+++ b/components/rpc/common/test/mock_rpc_interface.cpp
@@ -5,34 +5,34 @@
#include <CppUTestExt/MockSupport.h>
#include "mock_rpc_interface.h"
-#include "call_req_comparator.h"
+#include "rpc_request_comparator.h"
-static call_req_comparator req_comparator(call_req_comparator::mode_ignore_opstatus);
+static rpc_request_comparator req_comparator(rpc_request_comparator::mode_ignore_opstatus);
void mock_rpc_interface_init(void)
{
mock().installComparator("call_req", req_comparator);
}
-void expect_mock_rpc_interface_receive(struct rpc_interface *iface,
- const struct call_req *req, rpc_status_t result)
+void expect_mock_rpc_interface_receive(void *context,
+ const struct rpc_request *req, rpc_status_t result)
{
mock().expectOneCall("rpc_interface_receive").
- onObject(iface).
- withOutputParameterReturning("opstatus", &req->opstatus, sizeof(req->opstatus)).
- withOutputParameterReturning("resp_buf_data_len", &req->resp_buf.data_len,
- sizeof(req->resp_buf.data_len)).
+ onObject(context).
+ withOutputParameterReturning("service_status", &req->service_status, sizeof(req->service_status)).
+ withOutputParameterReturning("resp_buf_data_len", &req->response.data_length,
+ sizeof(req->response.data_length)).
withParameterOfType("call_req", "req", req).
andReturnValue(result);
}
-rpc_status_t mock_rpc_interface_receive(struct rpc_interface *iface,
- struct call_req *req)
+rpc_status_t mock_rpc_interface_receive(void *context,
+ struct rpc_request *req)
{
return mock().actualCall("rpc_interface_receive").
- onObject(iface).
- withOutputParameter("opstatus", &req->opstatus).
- withOutputParameter("resp_buf_data_len", &req->resp_buf.data_len).
+ onObject(context).
+ withOutputParameter("service_status", &req->service_status).
+ withOutputParameter("resp_buf_data_len", &req->response.data_length).
withParameterOfType("call_req", "req", req).
returnIntValue();
}
diff --git a/components/rpc/common/test/mock_rpc_interface.h b/components/rpc/common/test/mock_rpc_interface.h
index 7e80c4a07..d24e71f92 100644
--- a/components/rpc/common/test/mock_rpc_interface.h
+++ b/components/rpc/common/test/mock_rpc_interface.h
@@ -6,7 +6,7 @@
#ifndef MOCK_RPC_INTERFACE_H_
#define MOCK_RPC_INTERFACE_H_
-#include "../endpoint/rpc_interface.h"
+#include "../endpoint/rpc_service_interface.h"
#ifdef __cplusplus
extern "C" {
@@ -14,11 +14,10 @@ extern "C" {
void mock_rpc_interface_init(void);
-void expect_mock_rpc_interface_receive(struct rpc_interface *iface,
- const struct call_req *req, rpc_status_t result);
+void expect_mock_rpc_interface_receive(void *context, const struct rpc_request *req,
+ rpc_status_t result);
-rpc_status_t mock_rpc_interface_receive(struct rpc_interface *iface,
- struct call_req *req);
+rpc_status_t mock_rpc_interface_receive(void *context, struct rpc_request *req);
#ifdef __cplusplus
}
diff --git a/components/rpc/common/test/rpc_buffer_comparator.h b/components/rpc/common/test/rpc_buffer_comparator.h
new file mode 100644
index 000000000..93d41be1b
--- /dev/null
+++ b/components/rpc/common/test/rpc_buffer_comparator.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef RPC_BUFFER_COMPARATOR_H_
+#define RPC_BUFFER_COMPARATOR_H_
+
+#include <CppUTestExt/MockSupport.h>
+#include "../endpoint/rpc_service_interface.h"
+
+class rpc_buffer_comparator : public MockNamedValueComparator
+{
+public:
+ enum check_mode {
+ mode_normal = 0,
+ mode_ignore_data_len
+ };
+
+ explicit rpc_buffer_comparator(check_mode mode = mode_normal) : mode(mode)
+ {
+ }
+
+ virtual bool isEqual(const void *object1, const void *object2)
+ {
+ struct rpc_buffer *buf1 = (struct rpc_buffer *)object1;
+ struct rpc_buffer *buf2 = (struct rpc_buffer *)object2;
+
+ return (buf1->data == buf2->data) &&
+ (buf1->size == buf2->size) &&
+ (mode == mode_ignore_data_len || buf1->data_length == buf2->data_length);
+ }
+
+ // LCOV_EXCL_START
+ virtual SimpleString valueToString(const void *object)
+ {
+ struct rpc_buffer *buf = (struct rpc_buffer *)object;
+
+ return StringFromFormat("<size = %zu, data_len = %zu%s, data = %p>",
+ buf->size, buf->data_length,
+ (mode == mode_ignore_data_len) ? " (ignored)" : "",
+ buf->data);
+ }
+ // LCOV_EXCL_STOP
+
+private:
+ check_mode mode;
+};
+
+#endif /* RPC_BUFFER_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/rpc_request_comparator.h b/components/rpc/common/test/rpc_request_comparator.h
new file mode 100644
index 000000000..9a7467189
--- /dev/null
+++ b/components/rpc/common/test/rpc_request_comparator.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef CALL_REQ_COMPARATOR_H_
+#define CALL_REQ_COMPARATOR_H_
+
+#include <CppUTestExt/MockSupport.h>
+#include <inttypes.h>
+#include "rpc_buffer_comparator.h"
+
+class rpc_request_comparator : public MockNamedValueComparator
+{
+public:
+ enum check_mode {
+ mode_normal = 0,
+ mode_ignore_opstatus
+ };
+
+ explicit rpc_request_comparator(check_mode mode) : mode(mode)
+ {
+ }
+
+ virtual bool isEqual(const void *object1, const void *object2)
+ {
+ struct rpc_request *req1 = (struct rpc_request *)object1;
+ struct rpc_request *req2 = (struct rpc_request *)object2;
+ rpc_buffer_comparator buf_comparator_normal;
+ rpc_buffer_comparator buf_comparator_ignore_data_len(
+ rpc_buffer_comparator::mode_ignore_data_len);
+
+ return (req1->source_id == req2->source_id) &&
+ (req1->interface_id == req2->interface_id) &&
+ (req1->opcode == req2->opcode) &&
+ (req1->client_id == req2->client_id) &&
+ (mode == mode_ignore_opstatus || req1->service_status == req2->service_status) &&
+ buf_comparator_normal.isEqual(&req1->request, &req2->request) &&
+ buf_comparator_ignore_data_len.isEqual(&req1->response, &req2->response);
+ }
+
+ // LCOV_EXCL_START
+ virtual SimpleString valueToString(const void *object)
+ {
+ struct rpc_request *req = (struct rpc_request *)object;
+ rpc_buffer_comparator buf_comparator_normal;
+ rpc_buffer_comparator buf_comparator_ignore_data_len(
+ rpc_buffer_comparator::mode_ignore_data_len);
+ SimpleString req_buf_str = buf_comparator_normal.valueToString(&req->request);
+ SimpleString resp_buf_str =
+ buf_comparator_ignore_data_len.valueToString(&req->response);
+
+ return StringFromFormat("caller_id = 0x%" PRIx32 ", interface_id = %" PRIu32 ", " \
+ "opcode = %" PRIu32 ", encoding = %" PRIu32 ", " \
+ "opstatus = 0x%" PRIx64 "%s, req_buf = %s, " \
+ "resp_buf = %s",
+ req->source_id, req->interface_id, req->opcode,
+ req->client_id, req->service_status,
+ (mode == mode_ignore_opstatus) ? " (ignore)" : "",
+ req_buf_str.asCharString(), resp_buf_str.asCharString());
+ }
+ // LCOV_EXCL_STOP
+
+private:
+ check_mode mode;
+};
+
+#endif /* CALL_REQ_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/test_mock_rpc_interface.cpp b/components/rpc/common/test/test_mock_rpc_interface.cpp
index f3390f05b..28bbf1426 100644
--- a/components/rpc/common/test/test_mock_rpc_interface.cpp
+++ b/components/rpc/common/test/test_mock_rpc_interface.cpp
@@ -23,39 +23,39 @@ TEST_GROUP(mock_rpc_interface)
mock().clear();
}
- struct rpc_interface iface;
+ struct rpc_service_interface iface;
};
TEST(mock_rpc_interface, receive)
{
- rpc_status_t res = TS_RPC_ERROR_INTERNAL;
- struct call_req expected_req = { 0 };
- struct call_req req = { 0 };
+ rpc_status_t res = RPC_ERROR_INTERNAL;
+ struct rpc_request expected_req = { 0 };
+ struct rpc_request req = { 0 };
iface.context = (void *)1;
iface.receive = mock_rpc_interface_receive;
- expected_req.caller_id = 0x01234567;
- expected_req.interface_id = 0x89abcdef;
- expected_req.opcode = 0xfedcba98;
- expected_req.encoding = 0x76543210;
- expected_req.opstatus = (rpc_opstatus_t)-1;
+ expected_req.source_id = 0x4567;
+ expected_req.interface_id = 0xef;
+ expected_req.opcode = 0xba98;
+ expected_req.client_id = 0x76543210;
+ expected_req.service_status = (service_status_t)-1;
- expected_req.req_buf.size = 1;
- expected_req.req_buf.data_len = 2;
- expected_req.req_buf.data = (void *)3;
+ expected_req.request.size = 1;
+ expected_req.request.data_length = 2;
+ expected_req.request.data = (uint8_t *)3;
- expected_req.resp_buf.size = 4;
- expected_req.resp_buf.data_len = 5;
- expected_req.resp_buf.data = (void *)6;
+ expected_req.response.size = 4;
+ expected_req.response.data_length = 5;
+ expected_req.response.data = (uint8_t *)6;
memcpy(&req, &expected_req, sizeof(req));
- req.opstatus = 0;
- req.resp_buf.data_len = 0;
+ req.service_status = 0;
+ req.response.data_length = 0;
expect_mock_rpc_interface_receive(&iface, &expected_req, res);
LONGS_EQUAL(res, mock_rpc_interface_receive(&iface, &req));
- UNSIGNED_LONGLONGS_EQUAL(expected_req.opstatus, req.opstatus);
- UNSIGNED_LONGLONGS_EQUAL(expected_req.resp_buf.data_len, req.resp_buf.data_len);
+ UNSIGNED_LONGLONGS_EQUAL(expected_req.service_status, req.service_status);
+ UNSIGNED_LONGLONGS_EQUAL(expected_req.response.data_length, req.response.data_length);
}
diff --git a/components/rpc/direct/direct_caller.c b/components/rpc/direct/direct_caller.c
index 61f25d786..e534abe6e 100644
--- a/components/rpc/direct/direct_caller.c
+++ b/components/rpc/direct/direct_caller.c
@@ -5,122 +5,114 @@
*/
#include "direct_caller.h"
-#include <rpc/common/endpoint/rpc_interface.h>
-#include <protocols/rpc/common/packed-c/status.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "components/rpc/common/interface/rpc_uuid.h"
#include <stdlib.h>
-#define DIRECT_CALLER_DEFAULT_REQ_BUF_SIZE (4096)
-#define DIRECT_CALLER_DEFAULT_RESP_BUF_SIZE (4096)
+struct direct_caller_context {
+ struct rpc_service_interface *service;
+};
-static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len);
-static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
- rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len);
-static void call_end(void *context, rpc_call_handle handle);
+static rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid);
-
-struct rpc_caller *direct_caller_init(struct direct_caller *s, struct rpc_interface *iface,
- size_t req_buf_size, size_t resp_buf_size)
+static rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id)
{
- struct rpc_caller *base = &s->rpc_caller;
-
- rpc_caller_init(base, s);
- base->call_begin = call_begin;
- base->call_invoke = call_invoke;
- base->call_end = call_end;
-
- s->rpc_interface = iface;
- s->caller_id = 0;
- s->is_call_transaction_in_progess = false;
- s->req_len = 0;
- s->req_buf_size = req_buf_size;
- s->resp_buf_size = resp_buf_size;
- s->req_buf = malloc(s->req_buf_size);
- s->resp_buf = malloc(s->resp_buf_size);
-
- if (!s->req_buf || !s->resp_buf) {
-
- /* Buffer allocation failed */
- base = NULL;
- direct_caller_deinit(s);
- }
-
- return base;
+ (void)endpoint_id;
+
+ return find_and_open_session(context, service_uuid);
}
-struct rpc_caller *direct_caller_init_default(struct direct_caller *s, struct rpc_interface *iface)
+static rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid)
{
- /* Initialise with default buffer sizes */
- return direct_caller_init(s, iface,
- DIRECT_CALLER_DEFAULT_REQ_BUF_SIZE,
- DIRECT_CALLER_DEFAULT_RESP_BUF_SIZE);
+ struct direct_caller_context *caller = (struct direct_caller_context *)context;
+
+ if (!rpc_uuid_equal(service_uuid, &caller->service->uuid))
+ return RPC_ERROR_NOT_FOUND;
+
+ return RPC_SUCCESS;
}
-void direct_caller_deinit(struct direct_caller *s)
+static rpc_status_t close_session(void *context)
{
- free(s->req_buf);
- s->req_buf = NULL;
- free(s->resp_buf);
- s->resp_buf = NULL;
+ return RPC_SUCCESS;
}
-static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len)
+static rpc_status_t create_shared_memory(void *context, size_t size,
+ struct rpc_caller_shared_memory *shared_memory)
{
- struct direct_caller *this_context = (struct direct_caller*)context;
- rpc_call_handle handle = NULL;
-
- if (!this_context->is_call_transaction_in_progess &&
- (req_len <= this_context->req_buf_size)) {
+ shared_memory->id = 0;
+ shared_memory->buffer = calloc(1, size);
+ shared_memory->size = size;
- this_context->is_call_transaction_in_progess = true;
-
- if (req_buf){
- *req_buf = this_context->req_buf;
- this_context->req_len = req_len;
- }
+ return RPC_SUCCESS;
+}
- handle = this_context;
- }
+static rpc_status_t release_shared_memory(void *context,
+ struct rpc_caller_shared_memory *shared_memory)
+{
+ free(shared_memory->buffer);
- return handle;
+ return RPC_SUCCESS;
}
-static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
- rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len)
+static rpc_status_t call(void *context, uint16_t opcode,
+ struct rpc_caller_shared_memory *shared_memory, size_t request_length,
+ size_t *response_length, service_status_t *service_status)
{
- struct direct_caller *this_context = (struct direct_caller*)context;
- rpc_status_t status = TS_RPC_ERROR_INVALID_TRANSACTION;
+ struct direct_caller_context *caller = (struct direct_caller_context *)context;
+ struct rpc_request rpc_request = { 0 };
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ rpc_request.source_id = 0;
+ rpc_request.opcode = opcode;
+ rpc_request.client_id = 0;
+ rpc_request.request.data = shared_memory->buffer;
+ rpc_request.request.data_length = request_length;
+ rpc_request.request.size = shared_memory->size;
+ rpc_request.response.data = shared_memory->buffer;
+ rpc_request.response.data_length = 0;
+ rpc_request.response.size = shared_memory->size;
+
+ status = rpc_service_receive(caller->service, &rpc_request);
+
+ *response_length = rpc_request.response.data_length;
+ *service_status = rpc_request.service_status;
+
+ return status;
+}
- if ((handle == this_context) && this_context->is_call_transaction_in_progess) {
+rpc_status_t direct_caller_init(struct rpc_caller_interface *caller,
+ struct rpc_service_interface *service)
+{
+ struct direct_caller_context *context = NULL;
- struct call_req req;
+ if (!caller || caller->context)
+ return RPC_ERROR_INVALID_VALUE;
- req.interface_id = 0;
- req.opcode = opcode;
- req.encoding = this_context->rpc_caller.encoding;
- req.caller_id = this_context->caller_id;
- req.opstatus = 0;
- req.req_buf = call_param_buf_init_full(this_context->req_buf,
- this_context->req_buf_size, this_context->req_len);
- req.resp_buf = call_param_buf_init_empty(this_context->resp_buf,
- this_context->resp_buf_size);
+ context = (struct direct_caller_context *)calloc(1, sizeof(struct direct_caller_context));
+ if (!context)
+ return RPC_ERROR_INTERNAL;
- status = rpc_interface_receive(this_context->rpc_interface, &req);
+ context->service = service;
- *resp_buf = this_context->resp_buf;
- *resp_len = call_req_get_resp_buf(&req)->data_len;
- *opstatus = call_req_get_opstatus(&req);
- }
+ caller->context = context;
+ caller->open_session = open_session;
+ caller->find_and_open_session = find_and_open_session;
+ caller->close_session = close_session;
+ caller->create_shared_memory = create_shared_memory;
+ caller->release_shared_memory = release_shared_memory;
+ caller->call = call;
- return status;
+ return RPC_SUCCESS;
}
-static void call_end(void *context, rpc_call_handle handle)
+rpc_status_t direct_caller_deinit(struct rpc_caller_interface *rpc_caller)
{
- struct direct_caller *this_context = (struct direct_caller*)context;
+ if (!rpc_caller || !rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
- if ((handle == this_context) && this_context->is_call_transaction_in_progess) {
+ free(rpc_caller->context);
- this_context->req_len = 0;
- this_context->is_call_transaction_in_progess = false;
- }
+ return RPC_SUCCESS;
}
diff --git a/components/rpc/direct/direct_caller.h b/components/rpc/direct/direct_caller.h
index fe5ac087f..e583ab3a5 100644
--- a/components/rpc/direct/direct_caller.h
+++ b/components/rpc/direct/direct_caller.h
@@ -7,40 +7,23 @@
#ifndef DIRECT_CALLER_H
#define DIRECT_CALLER_H
-#include <rpc_caller.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
+#include "rpc_caller.h"
+
+struct rpc_service_interface;
#ifdef __cplusplus
extern "C" {
#endif
-struct rpc_interface;
-
/** An rpc_caller that calls methods associated with a specific endpoint
* directly. Used when the caller and endpoint are running in the same
* execution context.
**/
-struct direct_caller
-{
- struct rpc_caller rpc_caller;
- struct rpc_interface *rpc_interface;
- uint32_t caller_id;
- bool is_call_transaction_in_progess;
- size_t req_len;
- size_t req_buf_size;
- size_t resp_buf_size;
- uint8_t *req_buf;
- uint8_t *resp_buf;
-};
-
-struct rpc_caller *direct_caller_init(struct direct_caller *s, struct rpc_interface *iface,
- size_t req_buf_size, size_t resp_buf_size);
-
-struct rpc_caller *direct_caller_init_default(struct direct_caller *s, struct rpc_interface *iface);
-
-void direct_caller_deinit(struct direct_caller *s);
+
+rpc_status_t direct_caller_init(struct rpc_caller_interface *caller,
+ struct rpc_service_interface *service);
+
+rpc_status_t direct_caller_deinit(struct rpc_caller_interface *caller);
#ifdef __cplusplus
}
diff --git a/components/rpc/dummy/dummy_caller.c b/components/rpc/dummy/dummy_caller.c
index da0f491d0..c7f1f01fb 100644
--- a/components/rpc/dummy/dummy_caller.c
+++ b/components/rpc/dummy/dummy_caller.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,64 +7,121 @@
#include "dummy_caller.h"
#include <stdlib.h>
-static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len);
-static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
- rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len);
-static void call_end(void *context, rpc_call_handle handle);
+struct dummy_caller_context {
+ rpc_status_t rpc_status;
+ service_status_t service_status;
+ uint8_t *req_buf;
+};
+rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid, uint16_t endpoint_id)
+{
+ (void)context;
+ (void)service_uuid;
+ (void)endpoint_id;
+
+ return RPC_SUCCESS;
+}
-struct rpc_caller *dummy_caller_init(struct dummy_caller *s,
- rpc_status_t rpc_status, rpc_opstatus_t opstatus)
+rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid)
{
- struct rpc_caller *base = &s->rpc_caller;
+ (void)context;
+ (void)service_uuid;
- rpc_caller_init(base, s);
- base->call_begin = call_begin;
- base->call_invoke = call_invoke;
- base->call_end = call_end;
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t close_session(void *context)
+{
+ struct dummy_caller_context *caller_context = (struct dummy_caller_context *)context;
- s->rpc_status = rpc_status;
- s->opstatus = opstatus;
- s->req_buf = NULL;
+ free(caller_context->req_buf);
- return base;
+ return RPC_SUCCESS;
}
-void dummy_caller_deinit(struct dummy_caller *s)
+static rpc_status_t create_shared_memory(void *context, size_t size,
+ struct rpc_caller_shared_memory *shared_memory)
{
- free(s->req_buf);
- s->req_buf = NULL;
+ struct dummy_caller_context *caller_context = (struct dummy_caller_context *)context;
+
+ if (caller_context->req_buf)
+ return RPC_ERROR_INVALID_STATE;
+
+ caller_context->req_buf = calloc(1, size);
+
+ shared_memory->id = 0;
+ shared_memory->buffer = caller_context->req_buf;
+ shared_memory->size = size;
+
+ return RPC_SUCCESS;
}
-static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len)
+static rpc_status_t release_shared_memory(void *context,
+ struct rpc_caller_shared_memory *shared_memory)
{
- struct dummy_caller *this_context = (struct dummy_caller*)context;
- rpc_call_handle handle = this_context;
+ struct dummy_caller_context *caller_context = (struct dummy_caller_context *)context;
+
+ if (shared_memory->buffer != caller_context->req_buf)
+ return RPC_ERROR_INVALID_VALUE;
- free(this_context->req_buf);
- this_context->req_buf = malloc(req_len);
- *req_buf = this_context->req_buf;
+ if (!caller_context->req_buf)
+ return RPC_ERROR_INVALID_STATE;
- return handle;
+ free(caller_context->req_buf);
+ caller_context->req_buf = NULL;
+
+ return RPC_ERROR_INTERNAL;
}
-static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
- rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len)
+static rpc_status_t call(void *context, uint16_t opcode,
+ struct rpc_caller_shared_memory *shared_memory, size_t request_length,
+ size_t *response_length, service_status_t *service_status)
{
- struct dummy_caller *this_context = (struct dummy_caller*)context;
+ struct dummy_caller_context *caller_context = (struct dummy_caller_context *)context;
- free(this_context->req_buf);
- this_context->req_buf = NULL;
+ (void)opcode;
+ (void)shared_memory;
+ (void)request_length;
- *resp_buf = NULL;
- *resp_len = 0;
- *opstatus = this_context->opstatus;
+ *response_length = 0;
+ *service_status = caller_context->rpc_status;
- return this_context->rpc_status;
+ return caller_context->rpc_status;
}
-static void call_end(void *context, rpc_call_handle handle)
+rpc_status_t dummy_caller_init(struct rpc_caller_interface *rpc_caller, rpc_status_t rpc_status,
+ service_status_t service_status)
{
- (void)context;
- (void)handle;
+ struct dummy_caller_context *context = NULL;
+
+ if (!rpc_caller || rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ context = (struct dummy_caller_context *)calloc(1, sizeof(struct dummy_caller_context));
+ if (!context)
+ return RPC_ERROR_INTERNAL;
+
+ context->rpc_status = rpc_status;
+ context->service_status = service_status;
+ context->req_buf = NULL;
+
+ rpc_caller->context = context;
+ rpc_caller->open_session = open_session;
+ rpc_caller->find_and_open_session = find_and_open_session;
+ rpc_caller->close_session = close_session;
+ rpc_caller->create_shared_memory = create_shared_memory;
+ rpc_caller->release_shared_memory = release_shared_memory;
+ rpc_caller->call = call;
+
+ return RPC_SUCCESS;
}
+
+rpc_status_t dummy_caller_deinit(struct rpc_caller_interface *rpc_caller)
+{
+ if (!rpc_caller || !rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ free(rpc_caller->context);
+
+ return RPC_SUCCESS;
+} \ No newline at end of file
diff --git a/components/rpc/dummy/dummy_caller.h b/components/rpc/dummy/dummy_caller.h
index b93c02f5f..a7522d837 100644
--- a/components/rpc/dummy/dummy_caller.h
+++ b/components/rpc/dummy/dummy_caller.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,7 +7,7 @@
#ifndef DUMMY_CALLER
#define DUMMY_CALLER
-#include <rpc_caller.h>
+#include "rpc_caller.h"
#include <stdint.h>
#ifdef __cplusplus
@@ -22,17 +22,10 @@ extern "C" {
* established but a client doesn't wish to treat the condition
* as a fatal error.
*/
-struct dummy_caller
-{
- struct rpc_caller rpc_caller;
- rpc_status_t rpc_status;
- rpc_opstatus_t opstatus;
- uint8_t *req_buf;
-};
-struct rpc_caller *dummy_caller_init(struct dummy_caller *s,
- rpc_status_t rpc_status, rpc_opstatus_t opstatus);
-void dummy_caller_deinit(struct dummy_caller *s);
+rpc_status_t dummy_caller_init(struct rpc_caller_interface *caller, rpc_status_t rpc_status,
+ service_status_t service_status);
+rpc_status_t dummy_caller_deinit(struct rpc_caller_interface *caller);
#ifdef __cplusplus
}
diff --git a/components/rpc/ffarpc/caller/linux/component.cmake b/components/rpc/ffarpc/caller/linux/component.cmake
deleted file mode 100644
index ec5387c95..000000000
--- a/components/rpc/ffarpc/caller/linux/component.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-if(NOT DEFINED TGT)
- message(FATAL_ERROR "mandatory parameter TGT is not defined.")
-endif()
-
-include(${TS_ROOT}/external/LinuxFFAUserShim/LinuxFFAUserShim.cmake)
-
-target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/ffarpc_caller.c"
-)
-
-target_include_directories(${TGT} PRIVATE
- "${LINUX_FFA_USER_SHIM_INCLUDE_DIR}"
-)
diff --git a/components/rpc/ffarpc/caller/linux/ffarpc_caller.c b/components/rpc/ffarpc/caller/linux/ffarpc_caller.c
deleted file mode 100644
index 1464a8ae7..000000000
--- a/components/rpc/ffarpc/caller/linux/ffarpc_caller.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "ffarpc_caller.h"
-#include <arm_ffa_user.h>
-#include <rpc/ffarpc/endpoint/ffarpc_call_args.h>
-#include <rpc/ffarpc/endpoint/ffarpc_call_ops.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define KERNEL_MOD_REQ_VER_MAJOR 2
-#define KERNEL_MOD_REQ_VER_MINOR 0
-#define KERNEL_MOD_REQ_VER_PATCH 0
-
-#define DEFAULT_SHMEM_BUF_SIZE (4096)
-
-static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len);
-static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
- rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len);
-static void call_end(void *context, rpc_call_handle handle);
-
-static int kernel_write_req_buf(struct ffarpc_caller *s);
-static int kernel_read_resp_buf(struct ffarpc_caller *s);
-static int share_mem_with_partition(struct ffarpc_caller *s);
-static int unshare_mem_with_partition(struct ffarpc_caller *s);
-
-bool ffarpc_caller_check_version(void)
-{
- FILE *f;
- char mod_name[64];
- int ver_major, ver_minor, ver_patch;
- bool mod_loaded = false;
-
- f = fopen("/proc/modules", "r");
- if (!f) {
- printf("error: cannot open /proc/modules\n");
- return false;
- }
-
- while (fscanf(f, "%64s %*[^\n]\n", mod_name) != EOF) {
- if (!strcmp(mod_name, "arm_ffa_user")) {
- mod_loaded = true;
- break;
- }
- }
-
- fclose(f);
-
- if (!mod_loaded) {
- printf("error: kernel module not loaded\n");
- return false;
- }
-
- f = fopen("/sys/module/arm_ffa_user/version", "r");
- if (f) {
- fscanf(f, "%d.%d.%d", &ver_major, &ver_minor, &ver_patch);
- fclose(f);
- } else {
- /*
- * Fallback for the initial release of the kernel module, where
- * the version definition was missing.
- */
- ver_major = 1;
- ver_minor = 0;
- ver_patch = 0;
- }
-
- if (ver_major != KERNEL_MOD_REQ_VER_MAJOR)
- goto err;
-
- if (ver_minor < KERNEL_MOD_REQ_VER_MINOR)
- goto err;
-
- if (ver_minor == KERNEL_MOD_REQ_VER_MINOR)
- if (ver_patch < KERNEL_MOD_REQ_VER_PATCH)
- goto err;
-
- return true;
-
-err:
- printf("error: kernel module is v%d.%d.%d but required v%d.%d.%d\n",
- ver_major, ver_minor, ver_patch, KERNEL_MOD_REQ_VER_MAJOR,
- KERNEL_MOD_REQ_VER_MINOR, KERNEL_MOD_REQ_VER_PATCH);
-
- return false;
-}
-
-struct rpc_caller *ffarpc_caller_init(struct ffarpc_caller *s, const char *device_path)
-{
- struct rpc_caller *base = &s->rpc_caller;
-
- rpc_caller_init(base, s);
- base->call_begin = call_begin;
- base->call_invoke = call_invoke;
- base->call_end = call_end;
-
- s->device_path = device_path;
- s->fd = -1;
- s->dest_partition_id = 0;
- s->dest_iface_id = 0;
- s->shared_mem_handle = 0;
- s->shared_mem_required_size = DEFAULT_SHMEM_BUF_SIZE;
- s->req_buf = NULL;
- s->req_len = 0;
- s->resp_buf = NULL;
- s->resp_len = 0;
- s->is_call_transaction_in_progess = false;
-
- return base;
-}
-
-void ffarpc_caller_deinit(struct ffarpc_caller *s)
-{
- s->rpc_caller.context = NULL;
- s->rpc_caller.call_begin = NULL;
- s->rpc_caller.call_invoke = NULL;
- s->rpc_caller.call_end = NULL;
-
- call_end(s, s);
- ffarpc_caller_close(s);
-}
-
-size_t ffarpc_caller_discover(const struct ffarpc_caller *s, const struct uuid_canonical *uuid,
- uint16_t *partition_ids, size_t discover_limit)
-{
- size_t discover_count = 0;
-
- if (uuid && partition_ids && s->device_path) {
- int fd;
-
- fd = open(s->device_path, O_RDWR);
-
- if (fd >= 0) {
- int ioctl_status;
- struct ffa_ioctl_ep_desc discovered_partition;
-
- discovered_partition.uuid_ptr = (uintptr_t)&uuid->characters;
- discovered_partition.id = 0;
-
- ioctl_status = ioctl(fd, FFA_IOC_GET_PART_ID, &discovered_partition);
-
- if ((ioctl_status == 0) && (discover_count < discover_limit)) {
- partition_ids[discover_count] = discovered_partition.id;
- ++discover_count;
- }
-
- close(fd);
- }
- }
-
- return discover_count;
-}
-
-int ffarpc_caller_open(struct ffarpc_caller *s, uint16_t dest_partition_id, uint16_t dest_iface_id)
-{
- int ioctl_status = -1;
- struct ffa_ioctl_shm_desc shm_desc = {.dst_id = dest_partition_id};
-
- if (s->device_path) {
-
- s->fd = open(s->device_path, O_RDWR);
-
- if (s->fd >= 0) {
- /* Allocate resource for session */
- ioctl_status = ioctl(s->fd, FFA_IOC_SHM_INIT, &shm_desc);
-
- if (ioctl_status == 0) {
- /* Session successfully opened */
- s->dest_partition_id = dest_partition_id;
- s->dest_iface_id = dest_iface_id;
- s->shared_mem_handle = shm_desc.handle;
- ioctl_status = share_mem_with_partition(s);
- }
-
- if (ioctl_status != 0) {
- /* Resource allocation or sharing error */
- close(s->fd);
- s->fd = -1;
- }
- }
- }
-
- return ioctl_status;
-}
-
-int ffarpc_caller_close(struct ffarpc_caller *s)
-{
- int ioctl_status = -1;
- struct ffa_ioctl_shm_desc shm_desc = {
- .dst_id = s->dest_partition_id,
- .handle = s->shared_mem_handle,
- };
-
- if (s->fd >= 0) {
-
- unshare_mem_with_partition(s);
- ioctl_status = ioctl(s->fd, FFA_IOC_SHM_DEINIT, &shm_desc);
- close(s->fd);
- s->fd = -1;
- s->dest_partition_id = 0;
- }
-
- return ioctl_status;
-}
-
-static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len)
-{
- rpc_call_handle handle = NULL;
- struct ffarpc_caller *s = (struct ffarpc_caller*)context;
-
- if (!s->is_call_transaction_in_progess) {
-
- s->is_call_transaction_in_progess = true;
- handle = s;
-
- if (req_len > 0) {
-
- s->req_buf = malloc(req_len);
-
- if (s->req_buf) {
-
- *req_buf = s->req_buf;
- s->req_len = req_len;
- }
- else {
- /* Failed to allocate req buffer */
- handle = NULL;
- s->is_call_transaction_in_progess = false;
- }
- }
- else {
-
- *req_buf = NULL;
- s->req_buf = NULL;
- s->req_len = req_len;
- }
- }
-
- return handle;
-}
-
-static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
- rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len)
-{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct ffarpc_caller *s = (struct ffarpc_caller*)context;
-
- if ((handle == s) && s->is_call_transaction_in_progess) {
- int kernel_op_status = 0;
-
- if (s->req_len > 0) {
- kernel_op_status = kernel_write_req_buf(s);
- }
-
- if (kernel_op_status == 0) {
- /* Make direct call to send the request */
- struct ffa_ioctl_msg_args direct_msg;
- memset(&direct_msg, 0, sizeof(direct_msg));
-
- direct_msg.dst_id = s->dest_partition_id;
- direct_msg.args[FFA_CALL_ARGS_IFACE_ID_OPCODE] =
- FFA_CALL_ARGS_COMBINE_IFACE_ID_OPCODE(s->dest_iface_id, opcode);
- direct_msg.args[FFA_CALL_ARGS_REQ_DATA_LEN] = (uint64_t)s->req_len;
- direct_msg.args[FFA_CALL_ARGS_ENCODING] = s->rpc_caller.encoding;
-
- /* Initialise the caller ID. Depending on the call path, this may
- * be overridden by a higher privilege execution level, based on its
- * perspective of the caller identity.
- */
- direct_msg.args[FFA_CALL_ARGS_CALLER_ID] = 0;
-
- kernel_op_status = ioctl(s->fd, FFA_IOC_MSG_SEND, &direct_msg);
-
- if (kernel_op_status == 0) {
- /* Send completed normally - ffa return args in msg_args struct */
- s->resp_len = (size_t)direct_msg.args[FFA_CALL_ARGS_RESP_DATA_LEN];
- rpc_status = (rpc_status_t)direct_msg.args[FFA_CALL_ARGS_RESP_RPC_STATUS];
- *opstatus = (rpc_opstatus_t)((int32_t)direct_msg.args[FFA_CALL_ARGS_RESP_OP_STATUS]);
-
- if (s->resp_len > 0) {
- s->resp_buf = malloc(s->resp_len);
-
- if (s->resp_buf) {
- kernel_op_status = kernel_read_resp_buf(s);
-
- if (kernel_op_status != 0) {
- /* Failed to read response buffer */
- rpc_status = TS_RPC_ERROR_INTERNAL;
- }
- }
- else {
- /* Failed to allocate response buffer */
- s->resp_len = 0;
- rpc_status = TS_RPC_ERROR_INTERNAL;
- }
- }
- else {
- /* No response parameters */
- s->resp_buf = NULL;
- }
-
- *resp_len = s->resp_len;
- *resp_buf = s->resp_buf;
- }
- }
- }
-
- return rpc_status;
-}
-
-static void call_end(void *context, rpc_call_handle handle)
-{
- struct ffarpc_caller *s = (struct ffarpc_caller*)context;
-
- if ((handle == s) && s->is_call_transaction_in_progess) {
-
- /* Call transaction complete so free resource */
- free(s->req_buf);
- s->req_buf = NULL;
- s->req_len = 0;
-
- free(s->resp_buf);
- s->resp_buf = NULL;
- s->resp_len = 0;
-
- s->is_call_transaction_in_progess = false;
- }
-}
-
-static int kernel_write_req_buf(struct ffarpc_caller *s) {
-
- int ioctl_status;
- struct ffa_ioctl_buf_desc req_descr;
-
- req_descr.buf_ptr = (uintptr_t)s->req_buf;
- req_descr.buf_len = s->req_len;
- req_descr.dst_id = s->dest_partition_id;
- ioctl_status = ioctl(s->fd, FFA_IOC_SHM_WRITE, &req_descr);
-
- return ioctl_status;
-}
-
-
-static int kernel_read_resp_buf(struct ffarpc_caller *s) {
-
- int ioctl_status;
- struct ffa_ioctl_buf_desc resp_descr;
-
- resp_descr.buf_ptr = (uintptr_t)s->resp_buf;
- resp_descr.buf_len = s->resp_len;
- resp_descr.dst_id = s->dest_partition_id;
- ioctl_status = ioctl(s->fd, FFA_IOC_SHM_READ, &resp_descr);
-
- return ioctl_status;
-}
-
-static int share_mem_with_partition(struct ffarpc_caller *s) {
-
- int ioctl_status;
- struct ffa_ioctl_msg_args direct_msg;
- memset(&direct_msg, 0, sizeof(direct_msg));
-
- direct_msg.dst_id = s->dest_partition_id;
- direct_msg.args[FFA_CALL_ARGS_IFACE_ID_OPCODE] =
- FFA_CALL_ARGS_COMBINE_IFACE_ID_OPCODE(FFA_CALL_MGMT_IFACE_ID, FFA_CALL_OPCODE_SHARE_BUF);
- direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_LSW] = (uint32_t)s->shared_mem_handle;
- direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_MSW] = (uint32_t)(s->shared_mem_handle >> 32);
- direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_SIZE] = (uint64_t)s->shared_mem_required_size;
-
- ioctl_status = ioctl(s->fd, FFA_IOC_MSG_SEND, &direct_msg);
-
- return ioctl_status;
-}
-
-static int unshare_mem_with_partition(struct ffarpc_caller *s) {
-
- int ioctl_status;
- struct ffa_ioctl_msg_args direct_msg;
- memset(&direct_msg, 0, sizeof(direct_msg));
-
- direct_msg.dst_id = s->dest_partition_id;
- direct_msg.args[FFA_CALL_ARGS_IFACE_ID_OPCODE] =
- FFA_CALL_ARGS_COMBINE_IFACE_ID_OPCODE(FFA_CALL_MGMT_IFACE_ID, FFA_CALL_OPCODE_UNSHARE_BUF);
- direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_LSW] = (uint32_t)s->shared_mem_handle;
- direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_MSW] = (uint32_t)(s->shared_mem_handle >> 32);
-
- ioctl_status = ioctl(s->fd, FFA_IOC_MSG_SEND, &direct_msg);
-
- return ioctl_status;
-}
diff --git a/components/rpc/ffarpc/caller/linux/ffarpc_caller.h b/components/rpc/ffarpc/caller/linux/ffarpc_caller.h
deleted file mode 100644
index b40e20bc3..000000000
--- a/components/rpc/ffarpc/caller/linux/ffarpc_caller.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef FFARPC_CALLER_H
-#define FFARPC_CALLER_H
-
-#include <common/uuid/uuid.h>
-#include <rpc_caller.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * An RPC caller for Linux user-space clients. Uses the FFA kernel driver
- * to communicate with RPC endpoints deployed in partitions accessible
- * via FFA.
- */
-struct ffarpc_caller {
- struct rpc_caller rpc_caller;
- int fd;
- const char *device_path;
- uint16_t dest_partition_id;
- uint16_t dest_iface_id;
- uint64_t shared_mem_handle;
- size_t shared_mem_required_size;
- uint8_t *req_buf;
- uint8_t *resp_buf;
- size_t req_len;
- size_t resp_len;
- bool is_call_transaction_in_progess;
-};
-
-bool ffarpc_caller_check_version(void);
-struct rpc_caller *ffarpc_caller_init(struct ffarpc_caller *s, const char *device_path);
-void ffarpc_caller_deinit(struct ffarpc_caller *s);
-size_t ffarpc_caller_discover(const struct ffarpc_caller *s, const struct uuid_canonical *uuid,
- uint16_t *partition_ids, size_t discover_limit);
-int ffarpc_caller_open(struct ffarpc_caller *s, uint16_t dest_partition_id, uint16_t dest_iface_id);
-int ffarpc_caller_close(struct ffarpc_caller *s);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FFARPC_CALLER_H */
diff --git a/components/rpc/ffarpc/caller/sp/ffarpc_caller.c b/components/rpc/ffarpc/caller/sp/ffarpc_caller.c
deleted file mode 100644
index 250b17814..000000000
--- a/components/rpc/ffarpc/caller/sp/ffarpc_caller.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "ffarpc_caller.h"
-#include "ffarpc_sp_call_args.h"
-#include <components/rpc/ffarpc/endpoint/ffarpc_call_ops.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <ffa_api.h>
-#include <sp_memory_management.h>
-#include <sp_messaging.h>
-#include <sp_rxtx.h>
-#include <trace.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-
-uint8_t shared_buffer[4096] __aligned(4096);
-extern uint16_t own_id; //TODO: replace this with nicer solution
-
-static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len)
-{
- struct ffarpc_caller *this_context = (struct ffarpc_caller *)context;
- rpc_call_handle handle = NULL;
-
- if (req_buf == NULL) {
- EMSG("call_begin(): invalid arguments");
- goto out;
- }
-
- if (this_context->is_call_transaction_in_progess) {
- EMSG("call_begin(): transaction already in progress");
- goto out;
- }
-
- if (req_len > UINT32_MAX) {
- EMSG("call_begin(): req_len too big");
- goto out;
- }
-
- this_context->is_call_transaction_in_progess = true;
- handle = this_context;
-
- if (req_len > 0) {
- this_context->req_buf = shared_buffer;
- *req_buf = this_context->req_buf;
- this_context->req_len = req_len;
- } else {
- *req_buf = NULL;
- this_context->req_buf = NULL;
- this_context->req_len = req_len;
- }
-out:
- return handle;
-}
-
-static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
- rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len)
-{
- struct ffarpc_caller *this_context = (struct ffarpc_caller *)context;
- sp_result sp_res = SP_RESULT_OK;
- struct sp_msg req = { 0 };
- struct sp_msg resp = { 0 };
- rpc_status_t status = TS_RPC_ERROR_INTERNAL;
-
- if (handle != this_context || opstatus == NULL ||
- resp_buf == NULL || resp_len == NULL) {
- EMSG("call_invoke(): invalid arguments");
- status = TS_RPC_ERROR_INVALID_PARAMETER;
- goto out;
- }
-
- if (!this_context->is_call_transaction_in_progess) {
- EMSG("call_invoke(): transaction was not started");
- status = TS_RPC_ERROR_NOT_READY;
- goto out;
- }
-
- req.destination_id = this_context->dest_partition_id;
- req.source_id = own_id;
- req.args[SP_CALL_ARGS_IFACE_ID_OPCODE] =
- FFA_CALL_ARGS_COMBINE_IFACE_ID_OPCODE(this_context->dest_partition_id, opcode);
- //TODO: downcast problem?
- req.args[SP_CALL_ARGS_REQ_DATA_LEN] = (uint32_t)this_context->req_len;
- req.args[SP_CALL_ARGS_ENCODING] = this_context->rpc_caller.encoding;
-
- /* Initialise the caller ID. Depending on the call path, this may
- * be overridden by a higher privilege execution level, based on its
- * perspective of the caller identity.
- */
- req.args[SP_CALL_ARGS_CALLER_ID] = 0;
-
- sp_res = sp_msg_send_direct_req(&req, &resp);
-
- if (sp_res != SP_RESULT_OK) {
- EMSG("sp_msg_send_direct_req(): error %"PRId32, sp_res);
- goto out;
- }
-
- this_context->resp_len = (size_t)resp.args[SP_CALL_ARGS_RESP_DATA_LEN];
- status = resp.args[SP_CALL_ARGS_RESP_RPC_STATUS];
- *opstatus = (rpc_status_t)((int32_t)resp.args[SP_CALL_ARGS_RESP_OP_STATUS]);
-
- if (this_context->resp_len > 0) {
- this_context->resp_buf = shared_buffer;
- } else {
- this_context->resp_buf = NULL;
- }
-
- *resp_buf = this_context->resp_buf;
- *resp_len = this_context->resp_len;
-out:
- return status;
-}
-
-static void call_end(void *context, rpc_call_handle handle)
-{
- struct ffarpc_caller *this_context = (struct ffarpc_caller *)context;
-
- if (handle != this_context) {
- EMSG("call_end(): invalid arguments");
- return;
- }
-
- this_context->req_buf = NULL;
- this_context->req_len = 0;
- this_context->resp_buf = NULL;
- this_context->resp_len = 0;
- this_context->is_call_transaction_in_progess = false;
-}
-
-struct rpc_caller *ffarpc_caller_init(struct ffarpc_caller *s)
-{
- struct rpc_caller *base = &s->rpc_caller;
-
- rpc_caller_init(base, s);
- base->call_begin = call_begin;
- base->call_invoke = call_invoke;
- base->call_end = call_end;
-
- s->dest_partition_id = 0;
- s->dest_iface_id = 0;
- s->shared_mem_handle = 0;
- s->shared_mem_required_size = sizeof(shared_buffer);
- s->req_buf = NULL;
- s->req_len = 0;
- s->resp_buf = NULL;
- s->resp_len = 0;
- s->is_call_transaction_in_progess = false;
-
- return base;
-}
-
-void ffarpc_caller_deinit(struct ffarpc_caller *s)
-{
- s->rpc_caller.context = NULL;
- s->rpc_caller.call_begin = NULL;
- s->rpc_caller.call_invoke = NULL;
- s->rpc_caller.call_end = NULL;
-}
-
-uint32_t ffarpc_caller_discover(const uint8_t *uuid, uint16_t *sp_ids, uint32_t sp_max_cnt)
-{
- ffa_result ffa_res;
- sp_result sp_res;
- const void *rx_buf_addr = NULL;
- size_t rx_buf_size = 0;
- uint32_t sp_cnt = 0;
- uint32_t i;
-
- if (uuid == NULL || sp_ids == NULL || sp_max_cnt == 0) {
- EMSG("ffarpc_caller_discover(): invalid arguments");
- goto out;
- }
-
- //TODO: not sure if this cast is acceptable
- ffa_res = ffa_partition_info_get((struct ffa_uuid *)uuid, &sp_cnt);
- if (ffa_res != FFA_OK) {
- EMSG("ffa_partition_info_get(): error %"PRId32, ffa_res);
- goto out;
- }
-
- sp_res = sp_rxtx_buffer_rx_get(&rx_buf_addr, &rx_buf_size);
- if (sp_res != SP_RESULT_OK) {
- EMSG("sp_rxtx_buffer_rx_get(): error %"PRId32, sp_res);
- goto out;
- }
-
- const struct ffa_partition_information *partitions =
- (const struct ffa_partition_information *)rx_buf_addr;
-
- for (i = 0; i < sp_cnt && i < sp_max_cnt; i++) {
- sp_ids[i] = partitions[i].partition_id;
- }
-
- ffa_res = ffa_rx_release();
- if (ffa_res != FFA_OK) {
- EMSG("ffa_rx_release(): error %"PRId32, ffa_res);
- goto out;
- }
-out:
- return sp_cnt;
-}
-
-int ffarpc_caller_open(struct ffarpc_caller *s, uint16_t dest_partition_id, uint16_t dest_iface_id)
-{
- //TODO: revise return type, error handling
- sp_result sp_res = SP_RESULT_OK;
- struct sp_msg req = { 0 };
- struct sp_msg resp = { 0 };
-
- struct sp_memory_descriptor desc = { };
- struct sp_memory_access_descriptor acc_desc = { };
- struct sp_memory_region region = { };
-
- uint64_t handle = 0;
-
- desc.sender_id = own_id;
- desc.memory_type = sp_memory_type_normal_memory;
- desc.mem_region_attr.normal_memory.cacheability = sp_cacheability_write_back;
- desc.mem_region_attr.normal_memory.shareability = sp_shareability_inner_shareable;
-
- acc_desc.data_access = sp_data_access_read_write;
- acc_desc.instruction_access = sp_instruction_access_not_specified;
- acc_desc.receiver_id = dest_partition_id;
-
- region.address = shared_buffer;
- region.page_count = 1;
-
- sp_res = sp_memory_share(&desc, &acc_desc, 1, &region, 1, &handle);
- if (sp_res != SP_RESULT_OK) {
- EMSG("sp_memory_share(): error %"PRId32, sp_res);
- return -1;
- }
-
- req.source_id = own_id;
- req.destination_id = dest_partition_id;
- req.args[SP_CALL_ARGS_IFACE_ID_OPCODE] =
- FFA_CALL_ARGS_COMBINE_IFACE_ID_OPCODE(FFA_CALL_MGMT_IFACE_ID, FFA_CALL_OPCODE_SHARE_BUF);
- req.args[SP_CALL_ARGS_SHARE_MEM_HANDLE_LSW] = (uint32_t)(handle & UINT32_MAX);
- req.args[SP_CALL_ARGS_SHARE_MEM_HANDLE_MSW] = (uint32_t)(handle >> 32);
- //TODO: downcast
- req.args[SP_CALL_ARGS_SHARE_MEM_SIZE] = (uint32_t)(s->shared_mem_required_size);
-
- sp_res = sp_msg_send_direct_req(&req, &resp);
-
- if (sp_res != SP_RESULT_OK) {
- EMSG("sp_msg_send_direct_req(): error %"PRId32, sp_res);
- return -1;
- }
-
- s->dest_partition_id = dest_partition_id;
- s->dest_iface_id = dest_iface_id;
- s->shared_mem_handle = handle;
-
- return 0;
-}
-
-int ffarpc_caller_close(struct ffarpc_caller *s)
-{
- //TODO: revise return type, error handling
- sp_result sp_res = SP_RESULT_OK;
- struct sp_msg req = { 0 };
- struct sp_msg resp = { 0 };
-
- uint32_t handle_lo, handle_hi;
-
- handle_lo = (uint32_t)(s->shared_mem_handle & UINT32_MAX);
- handle_hi = (uint32_t)(s->shared_mem_handle >> 32);
-
- req.source_id = own_id;
- req.destination_id = s->dest_partition_id;
- req.args[SP_CALL_ARGS_IFACE_ID_OPCODE] =
- FFA_CALL_ARGS_COMBINE_IFACE_ID_OPCODE(FFA_CALL_MGMT_IFACE_ID, FFA_CALL_OPCODE_UNSHARE_BUF);
- req.args[SP_CALL_ARGS_SHARE_MEM_HANDLE_LSW] = handle_lo;
- req.args[SP_CALL_ARGS_SHARE_MEM_HANDLE_MSW] = handle_hi;
-
- sp_res = sp_msg_send_direct_req(&req, &resp);
-
- if (sp_res != SP_RESULT_OK) {
- EMSG("sp_msg_send_direct_req(): error %"PRId32, sp_res);
- return -1;
- }
-
- sp_res = sp_memory_reclaim(s->shared_mem_handle, 0);
- if (sp_res != SP_RESULT_OK) {
- EMSG("sp_memory_reclaim(): error %"PRId32, sp_res);
- return -1;
- }
-
- s->dest_partition_id = 0;
- s->dest_iface_id = 0;
- s->shared_mem_handle = 0;
-
- return 0;
-}
diff --git a/components/rpc/ffarpc/caller/sp/ffarpc_caller.h b/components/rpc/ffarpc/caller/sp/ffarpc_caller.h
deleted file mode 100644
index a6c2fba53..000000000
--- a/components/rpc/ffarpc/caller/sp/ffarpc_caller.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef FFA_SERVICE_CALLER_H
-#define FFA_SERVICE_CALLER_H
-
-#include <rpc_caller.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct ffarpc_caller {
- struct rpc_caller rpc_caller;
- uint16_t dest_partition_id;
- uint16_t dest_iface_id;
- uint64_t shared_mem_handle;
- size_t shared_mem_required_size;
- uint8_t *req_buf;
- uint8_t *resp_buf;
- size_t req_len;
- size_t resp_len;
- bool is_call_transaction_in_progess;
-};
-
-struct rpc_caller *ffarpc_caller_init(struct ffarpc_caller *s);
-void ffarpc_caller_deinit(struct ffarpc_caller *s);
-uint32_t ffarpc_caller_discover(const uint8_t *uuid, uint16_t *sp_ids, uint32_t sp_max_cnt);
-int ffarpc_caller_open(struct ffarpc_caller *s, uint16_t dest_partition_id, uint16_t dest_iface_id);
-int ffarpc_caller_close(struct ffarpc_caller *s);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FFA_SERVICE_CALLER_H */
diff --git a/components/rpc/ffarpc/caller/sp/ffarpc_sp_call_args.h b/components/rpc/ffarpc/caller/sp/ffarpc_sp_call_args.h
deleted file mode 100644
index e85c9a9d6..000000000
--- a/components/rpc/ffarpc/caller/sp/ffarpc_sp_call_args.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#ifndef FFA_RPC_SP_CALL_ARGS_H_
-#define FFA_RPC_SP_CALL_ARGS_H_
-
-#include "components/rpc/ffarpc/endpoint/ffarpc_call_args.h"
-
-/*
- * sp_msg args is shifted by one compared to ffa_direct_msg because the first
- * parameter register (w3/w3) is used by the routing extension and it is not
- * included in sp_msg args.
- */
-#define FFA_TO_SP_CALL_OFFSET(offset) ((offset)-1)
-
-/* Common req & resp arg offests into sp_msg args structure */
-#define SP_CALL_ARGS_IFACE_ID_OPCODE \
- FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_IFACE_ID_OPCODE)
-
-/* Req arg offsets */
-#define SP_CALL_ARGS_REQ_DATA_LEN \
- FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_REQ_DATA_LEN)
-#define SP_CALL_ARGS_CALLER_ID FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_CALLER_ID)
-#define SP_CALL_ARGS_ENCODING FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_ENCODING)
-
-/* Resp arg offsets */
-#define SP_CALL_ARGS_RESP_DATA_LEN \
- FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_RESP_DATA_LEN)
-#define SP_CALL_ARGS_RESP_RPC_STATUS \
- FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_RESP_RPC_STATUS)
-#define SP_CALL_ARGS_RESP_OP_STATUS \
- FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_RESP_OP_STATUS)
-
-/* Share/unshare offsets */
-#define SP_CALL_ARGS_SHARE_MEM_HANDLE_LSW \
- FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_SHARE_MEM_HANDLE_LSW)
-#define SP_CALL_ARGS_SHARE_MEM_HANDLE_MSW \
- FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_SHARE_MEM_HANDLE_MSW)
-#define SP_CALL_ARGS_SHARE_MEM_SIZE \
- FFA_TO_SP_CALL_OFFSET(FFA_CALL_ARGS_SHARE_MEM_SIZE)
-
-#endif /* FFA_RPC_SP_CALL_ARGS_H_ */
diff --git a/components/rpc/ffarpc/endpoint/ffarpc_call_args.h b/components/rpc/ffarpc/endpoint/ffarpc_call_args.h
deleted file mode 100644
index 1d2d9c93d..000000000
--- a/components/rpc/ffarpc/endpoint/ffarpc_call_args.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef FFA_CALL_ARGS_H
-#define FFA_CALL_ARGS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Defines convention for use of FFA direct call arguments by
- * the SP service framework. This header file is used by the
- * normal world RPC caller and the RPC listener in the SP.
- */
-
-/* Macros for parameters carried in a single register */
-#define FFA_CALL_ARGS_COMBINE_IFACE_ID_OPCODE(i, o) \
- (((i) << 16) | ((o) & 0xffff))
-#define FFA_CALL_ARGS_EXTRACT_IFACE(reg) \
- ((reg) >> 16)
-#define FFA_CALL_ARGS_EXTRACT_OPCODE(reg) \
- ((reg) & 0xffff)
-
-/* Common req & resp arg offests into msg_args structure */
-#define FFA_CALL_ARGS_IFACE_ID_OPCODE (1)
-
-/* Req arg offsets */
-#define FFA_CALL_ARGS_REQ_DATA_LEN (2)
-#define FFA_CALL_ARGS_CALLER_ID (3)
-#define FFA_CALL_ARGS_ENCODING (4)
-
-/* Resp arg offsets */
-#define FFA_CALL_ARGS_RESP_DATA_LEN (2)
-#define FFA_CALL_ARGS_RESP_RPC_STATUS (3)
-#define FFA_CALL_ARGS_RESP_OP_STATUS (4)
-
-/* Share/unshare offsets */
-#define FFA_CALL_ARGS_SHARE_MEM_HANDLE_LSW (2)
-#define FFA_CALL_ARGS_SHARE_MEM_HANDLE_MSW (3)
-#define FFA_CALL_ARGS_SHARE_MEM_SIZE (4)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FFA_CALL_ARGS_H */
diff --git a/components/rpc/ffarpc/endpoint/ffarpc_call_ep.c b/components/rpc/ffarpc/endpoint/ffarpc_call_ep.c
deleted file mode 100644
index 17f957c23..000000000
--- a/components/rpc/ffarpc/endpoint/ffarpc_call_ep.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "components/rpc/ffarpc/caller/sp/ffarpc_sp_call_args.h"
-#include "ffarpc_call_ep.h"
-#include "ffarpc_call_ops.h"
-#include <ffa_api.h>
-#include <sp_memory_management.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <trace.h>
-#include <stddef.h>
-
-/* TODO: remove this when own ID will be available in libsp */
-extern uint16_t own_id;
-
-static void set_resp_args(uint32_t *resp_args, uint32_t ifaceid_opcode, uint32_t data_len,
- rpc_status_t rpc_status, rpc_opstatus_t opstatus)
-{
- resp_args[SP_CALL_ARGS_IFACE_ID_OPCODE] = ifaceid_opcode;
- resp_args[SP_CALL_ARGS_RESP_DATA_LEN] = data_len;
- resp_args[SP_CALL_ARGS_RESP_RPC_STATUS] = rpc_status;
- resp_args[SP_CALL_ARGS_RESP_OP_STATUS] = (uint32_t)opstatus;
-}
-
-static void set_mgmt_resp_args(uint32_t *resp_args, uint32_t ifaceid_opcode,
- rpc_status_t rpc_status)
-{
- /*
- * Sets arguments for responses that originate from the ffa_call_ep
- * rather than from a higher layer service. These responses are not
- * associated with a shared buffer for any additional message payload.
- */
- set_resp_args(resp_args, ifaceid_opcode, 0, rpc_status, 0);
-}
-
-static int find_free_shm(struct ffa_call_ep *call_ep)
-{
- int i;
-
- if (!call_ep)
- return -1;
-
- for (i = 0; i < NUM_MAX_SESS; i++)
- if (!call_ep->shmem_buf[i]) {
- DMSG("shm slot %u allocated for %p", i, call_ep);
- return i;
- }
-
- EMSG("shm slot allocation failed");
- return -1;
-}
-
-static int find_shm(struct ffa_call_ep *call_ep, uint16_t source_id)
-{
- int i;
-
- if (!call_ep)
- return -1;
-
- for (i = 0; i < NUM_MAX_SESS; i++)
- if (call_ep->src_id[i] == source_id)
- return i;
-
- EMSG("shm not found for source 0x%x", source_id);
- return -1;
-}
-
-static void init_shmem_buf(struct ffa_call_ep *call_ep, uint16_t source_id,
- const uint32_t *req_args, uint32_t *resp_args)
-{
- sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
- struct sp_memory_descriptor desc = { };
- struct sp_memory_access_descriptor acc_desc = { };
- struct sp_memory_region region = { };
- uint32_t in_region_count = 0;
- uint32_t out_region_count = 1;
- uint64_t handle = 0;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- int idx = find_free_shm(call_ep);
-
- if (idx < 0) {
- EMSG("shm init error");
- goto out;
- }
-
- desc.sender_id = source_id;
- desc.memory_type = sp_memory_type_not_specified;
- desc.flags.transaction_type = sp_memory_transaction_type_share;
- acc_desc.receiver_id = own_id;
- acc_desc.data_access = sp_data_access_read_write;
- handle = req_args[SP_CALL_ARGS_SHARE_MEM_HANDLE_MSW];
- handle = (handle << 32) | req_args[SP_CALL_ARGS_SHARE_MEM_HANDLE_LSW];
-
- sp_res = sp_memory_retrieve(&desc, &acc_desc, &region, in_region_count,
- &out_region_count, handle);
-
- if (sp_res == SP_RESULT_OK) {
- call_ep->shmem_buf[idx] = region.address;
- call_ep->shmem_buf_handle[idx] = handle;
- call_ep->shmem_buf_size[idx] = (size_t)req_args[SP_CALL_ARGS_SHARE_MEM_SIZE];
- call_ep->src_id[idx] = source_id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- } else {
- EMSG("memory retrieve error: %d", sp_res);
- }
-
-out:
- set_mgmt_resp_args(resp_args, req_args[SP_CALL_ARGS_IFACE_ID_OPCODE], rpc_status);
-}
-
-static void deinit_shmem_buf(struct ffa_call_ep *call_ep, uint16_t source_id,
- const uint32_t *req_args, uint32_t *resp_args)
-{
- sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- uint64_t handle;
- uint16_t endpoints[1] = { own_id };
- uint32_t endpoint_cnt = 1;
- struct sp_memory_transaction_flags flags = {
- .zero_memory = false,
- .operation_time_slicing = false,
- };
- int idx = find_shm(call_ep, source_id);
-
- if (idx < 0) {
- EMSG("shm deinit error");
- goto out;
- }
-
- handle = call_ep->shmem_buf_handle[idx];
-
- sp_res = sp_memory_relinquish(handle, endpoints, endpoint_cnt, &flags);
- if (sp_res == SP_RESULT_OK) {
- call_ep->shmem_buf[idx] = NULL;
- call_ep->shmem_buf_handle[idx] = 0;
- call_ep->shmem_buf_size[idx] = 0;
- call_ep->src_id[idx] = 0xffff;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- } else {
- EMSG("memory relinquish error: %d", sp_res);
- }
-
-out:
- set_mgmt_resp_args(resp_args, req_args[SP_CALL_ARGS_IFACE_ID_OPCODE], rpc_status);
-}
-
-static void handle_service_msg(struct ffa_call_ep *call_ep, uint16_t source_id,
- const uint32_t *req_args, uint32_t *resp_args)
-{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct call_req call_req;
-
- uint32_t ifaceid_opcode = req_args[SP_CALL_ARGS_IFACE_ID_OPCODE];
- int idx = find_shm(call_ep, source_id);
-
- if (idx < 0) {
- EMSG("handle service msg error");
- goto out;
- }
-
- call_req.caller_id = source_id;
- call_req.interface_id = FFA_CALL_ARGS_EXTRACT_IFACE(ifaceid_opcode);
- call_req.opcode = FFA_CALL_ARGS_EXTRACT_OPCODE(ifaceid_opcode);
- call_req.encoding = req_args[SP_CALL_ARGS_ENCODING];
-
- call_req.req_buf.data = call_ep->shmem_buf[idx];
- call_req.req_buf.data_len = req_args[SP_CALL_ARGS_REQ_DATA_LEN];
- call_req.req_buf.size = call_ep->shmem_buf_size[idx];
-
- call_req.resp_buf.data = call_ep->shmem_buf[idx];
- call_req.resp_buf.data_len = 0;
- call_req.resp_buf.size = call_ep->shmem_buf_size[idx];
-
- rpc_status = rpc_interface_receive(call_ep->iface, &call_req);
-
-out:
- set_resp_args(resp_args,
- ifaceid_opcode,
- call_req.resp_buf.data_len,
- rpc_status,
- call_req.opstatus);
-}
-
-static void handle_mgmt_msg(struct ffa_call_ep *call_ep, uint16_t source_id,
- const uint32_t *req_args, uint32_t *resp_args)
-{
- uint32_t ifaceid_opcode = req_args[SP_CALL_ARGS_IFACE_ID_OPCODE];
- uint32_t opcode = FFA_CALL_ARGS_EXTRACT_OPCODE(ifaceid_opcode);
-
- switch (opcode) {
- case FFA_CALL_OPCODE_SHARE_BUF:
- init_shmem_buf(call_ep, source_id, req_args, resp_args);
- break;
- case FFA_CALL_OPCODE_UNSHARE_BUF:
- deinit_shmem_buf(call_ep, source_id, req_args, resp_args);
- break;
- default:
- set_mgmt_resp_args(resp_args, ifaceid_opcode, TS_RPC_ERROR_INVALID_OPCODE);
- break;
- }
-}
-
-void ffa_call_ep_init(struct ffa_call_ep *ffa_call_ep, struct rpc_interface *iface)
-{
- int i;
-
- ffa_call_ep->iface = iface;
-
- for (i = 0; i < NUM_MAX_SESS; i++) {
- ffa_call_ep->shmem_buf_handle[i] = 0;
- ffa_call_ep->shmem_buf_size[i] = 0;
- ffa_call_ep->shmem_buf[i] = NULL;
- ffa_call_ep->src_id[i] = 0xffff;
- }
-}
-
-void ffa_call_ep_receive(struct ffa_call_ep *call_ep,
- const struct sp_msg *req_msg,
- struct sp_msg *resp_msg)
-{
- const uint32_t *req_args = req_msg->args;
- uint32_t *resp_args = resp_msg->args;
- int idx;
-
- uint16_t source_id = req_msg->source_id;
- uint32_t ifaceid_opcode = req_args[SP_CALL_ARGS_IFACE_ID_OPCODE];
-
- if (FFA_CALL_ARGS_EXTRACT_IFACE(ifaceid_opcode) == FFA_CALL_MGMT_IFACE_ID) {
- /* It's an RPC layer management request */
- handle_mgmt_msg(call_ep, source_id, req_args, resp_args);
- } else {
- /*
- * Assume anything else is a service request. Service requests
- * rely on a buffer being shared from the requesting client.
- * If it hasn't been set-up, fail the request.
- */
- idx = find_shm(call_ep, source_id);
-
- if (idx >= 0 && call_ep->shmem_buf[idx]) {
- handle_service_msg(call_ep, source_id, req_args, resp_args);
- } else {
- EMSG("shared buffer not found or NULL");
- set_mgmt_resp_args(resp_args, ifaceid_opcode, TS_RPC_ERROR_NOT_READY);
- }
- }
-}
diff --git a/components/rpc/ffarpc/endpoint/ffarpc_call_ep.h b/components/rpc/ffarpc/endpoint/ffarpc_call_ep.h
deleted file mode 100644
index df4417dab..000000000
--- a/components/rpc/ffarpc/endpoint/ffarpc_call_ep.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef FFA_CALL_EP_H
-#define FFA_CALL_EP_H
-
-#include <ffa_api.h>
-#include "sp_messaging.h"
-#include <components/rpc/common/endpoint/rpc_interface.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef NUM_MAX_SESS
-#define NUM_MAX_SESS (16)
-#endif
-
-struct ffa_call_ep {
- struct rpc_interface *iface;
- unsigned long shmem_buf_handle[NUM_MAX_SESS];
- volatile uint8_t *shmem_buf[NUM_MAX_SESS];
- size_t shmem_buf_size[NUM_MAX_SESS];
- uint16_t src_id[NUM_MAX_SESS];
- };
-
-void ffa_call_ep_init(struct ffa_call_ep *ffa_call_ep, struct rpc_interface *iface);
-void ffa_call_ep_receive(struct ffa_call_ep *call_ep,
- const struct sp_msg *req_msg,
- struct sp_msg *resp_msg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FFA_CALL_EP_H */
diff --git a/components/rpc/ffarpc/endpoint/ffarpc_call_ops.h b/components/rpc/ffarpc/endpoint/ffarpc_call_ops.h
deleted file mode 100644
index de22678e6..000000000
--- a/components/rpc/ffarpc/endpoint/ffarpc_call_ops.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef FFA_CALL_OPS_H
-#define FFA_CALL_OPS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Common opcodes used by the FFA based RPC layer for management operations */
-enum
-{
- FFA_CALL_OPCODE_SHARE_BUF = 0,
- FFA_CALL_OPCODE_UNSHARE_BUF = 1,
- FFA_CALL_OPCODE_LIMIT
-};
-
-/* Interface ID for FFA management interface */
-#define FFA_CALL_MGMT_IFACE_ID (0x1000)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FFA_CALL_OPS_H */
diff --git a/components/rpc/ffarpc/caller/sp/component.cmake b/components/rpc/http/caller/component.cmake
index 3bab840ee..570f19b6a 100644
--- a/components/rpc/ffarpc/caller/sp/component.cmake
+++ b/components/rpc/http/caller/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,6 +9,6 @@ if (NOT DEFINED TGT)
endif()
target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/ffarpc_caller.c"
+ "${CMAKE_CURRENT_LIST_DIR}/http_caller.c"
)
diff --git a/components/rpc/http/caller/http_caller.c b/components/rpc/http/caller/http_caller.c
new file mode 100644
index 000000000..120eef884
--- /dev/null
+++ b/components/rpc/http/caller/http_caller.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "http_caller.h"
+
+#include <assert.h>
+#include <curl/curl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "protocols/rpc/common/packed-c/header.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "trace.h"
+
+#define USER_AGENT "libcurl-agent/1.0"
+
+struct payload_buffer {
+ uint8_t *data;
+ size_t size;
+ size_t pos;
+};
+
+static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len);
+static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
+ rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len);
+static void call_end(void *context, rpc_call_handle handle);
+
+static size_t request_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ size_t bytes_requested = size * nmemb;
+ struct payload_buffer *buf = (struct payload_buffer *)userdata;
+
+ size_t bytes_remaining = buf->size - buf->pos;
+ size_t bytes_to_send = (bytes_remaining < bytes_requested) ? bytes_remaining :
+ bytes_requested;
+
+ memcpy(ptr, &buf->data[buf->pos], bytes_to_send);
+
+ buf->pos += bytes_to_send;
+
+ return bytes_to_send;
+}
+
+static size_t response_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ size_t bytes_received = size * nmemb;
+ struct payload_buffer *buf = (struct payload_buffer *)userdata;
+
+ buf->data = realloc(buf->data, buf->size + bytes_received);
+
+ if (buf->data) {
+ memcpy(&buf->data[buf->size], ptr, bytes_received);
+ buf->size += bytes_received;
+ } else {
+ EMSG("Out of memory");
+ bytes_received = 0;
+ }
+
+ return bytes_received;
+}
+
+static bool send_head_request(const char *url, struct payload_buffer *response_buf, long *http_code)
+{
+ assert(url);
+ assert(response_buf);
+
+ bool is_success = false;
+ CURL *curl_session = curl_easy_init();
+
+ *http_code = 0;
+
+ if (curl_session) {
+ curl_easy_setopt(curl_session, CURLOPT_URL, url);
+ curl_easy_setopt(curl_session, CURLOPT_NOBODY, 1L);
+ curl_easy_setopt(curl_session, CURLOPT_WRITEFUNCTION, response_callback);
+ curl_easy_setopt(curl_session, CURLOPT_WRITEDATA, (void *)response_buf);
+ curl_easy_setopt(curl_session, CURLOPT_USERAGENT, USER_AGENT);
+
+ CURLcode status = curl_easy_perform(curl_session);
+
+ if (status == CURLE_OK) {
+ status = curl_easy_getinfo(curl_session, CURLINFO_RESPONSE_CODE, http_code);
+ is_success = (status == CURLE_OK) && (*http_code >= 200) &&
+ (*http_code < 300);
+ }
+
+ curl_easy_cleanup(curl_session);
+ } else {
+ EMSG("Failed to init Curl session");
+ }
+
+ return is_success;
+}
+
+static bool send_put_request(const char *url, struct payload_buffer *request_buf,
+ struct payload_buffer *response_buf)
+{
+ bool is_success = false;
+
+ assert(url);
+ assert(request_buf);
+ assert(response_buf);
+
+ CURL *curl_session = curl_easy_init();
+
+ if (curl_session) {
+ curl_easy_setopt(curl_session, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt(curl_session, CURLOPT_URL, url);
+ curl_easy_setopt(curl_session, CURLOPT_READFUNCTION, request_callback);
+ curl_easy_setopt(curl_session, CURLOPT_READDATA, (void *)request_buf);
+ curl_easy_setopt(curl_session, CURLOPT_INFILESIZE_LARGE,
+ (curl_off_t)request_buf->size);
+ curl_easy_setopt(curl_session, CURLOPT_WRITEFUNCTION, response_callback);
+ curl_easy_setopt(curl_session, CURLOPT_WRITEDATA, (void *)response_buf);
+ curl_easy_setopt(curl_session, CURLOPT_USERAGENT, USER_AGENT);
+
+ CURLcode status = curl_easy_perform(curl_session);
+
+ if (status == CURLE_OK) {
+ long http_code = 0;
+
+ status =
+ curl_easy_getinfo(curl_session, CURLINFO_RESPONSE_CODE, &http_code);
+ is_success = (status == CURLE_OK) && (http_code >= 200) &&
+ (http_code < 300);
+ }
+
+ curl_easy_cleanup(curl_session);
+ } else {
+ EMSG("Failed to init Curl session");
+ }
+
+ return is_success;
+}
+
+static void prepare_call_url(const struct http_caller *s, unsigned int opcode, char *url_buf,
+ size_t url_buf_size)
+{
+ size_t base_url_len = strnlen(s->rpc_call_url, HTTP_CALLER_MAX_URL_LEN);
+
+ assert(base_url_len > 0);
+ assert(base_url_len < url_buf_size);
+
+ memset(url_buf, 0, url_buf_size);
+ memcpy(url_buf, s->rpc_call_url, base_url_len);
+
+ /* Ensure '/' is present before adding opcode */
+ if (url_buf[base_url_len - 1] != '/') {
+ url_buf[base_url_len] = '/';
+ base_url_len += 1;
+ }
+
+ size_t remaining_space = url_buf_size - base_url_len;
+ size_t opcode_len = snprintf(&url_buf[base_url_len], remaining_space, "%u", opcode);
+
+ assert(opcode_len < remaining_space);
+}
+
+struct rpc_caller *http_caller_init(struct http_caller *s)
+{
+ assert(s);
+
+ struct rpc_caller *base = &s->rpc_caller;
+
+ rpc_caller_init(base, s);
+ base->call_begin = call_begin;
+ base->call_invoke = call_invoke;
+ base->call_end = call_end;
+
+ memset(s->rpc_call_url, 0, sizeof(s->rpc_call_url));
+
+ s->req_body_size = 0;
+ s->req_body_buf = NULL;
+ s->resp_body_buf = NULL;
+
+ CURLcode status = curl_global_init(CURL_GLOBAL_ALL);
+
+ return (status == CURLE_OK) ? base : NULL;
+}
+
+void http_caller_deinit(struct http_caller *s)
+{
+ assert(s);
+
+ s->rpc_caller.context = NULL;
+ s->rpc_caller.call_begin = NULL;
+ s->rpc_caller.call_invoke = NULL;
+ s->rpc_caller.call_end = NULL;
+
+ call_end(s, s);
+}
+
+bool http_caller_probe(const char *url, long *http_code)
+{
+ assert(url);
+
+ struct payload_buffer response_buf;
+
+ response_buf.data = NULL;
+ response_buf.size = 0;
+
+ bool is_reached = send_head_request(url, &response_buf, http_code);
+
+ free(response_buf.data);
+
+ return is_reached;
+}
+
+int http_caller_open(struct http_caller *s, const char *rpc_call_url)
+{
+ assert(s);
+ assert(rpc_call_url);
+
+ strncpy(s->rpc_call_url, rpc_call_url, sizeof(s->rpc_call_url));
+
+ return 0;
+}
+
+int http_caller_close(struct http_caller *s)
+{
+ (void)s;
+ return 0;
+}
+
+static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len)
+{
+ assert(context);
+ assert(req_buf || !req_len);
+
+ rpc_call_handle handle = NULL;
+ struct http_caller *s = (struct http_caller *)context;
+
+ if (!s->req_body_buf) {
+ size_t req_body_size = sizeof(struct ts_rpc_req_hdr) + req_len;
+
+ s->req_body_buf = malloc(req_body_size);
+
+ if (s->req_body_buf) {
+ memset(s->req_body_buf, 0, req_body_size);
+
+ handle = s;
+ *req_buf = &s->req_body_buf[sizeof(struct ts_rpc_req_hdr)];
+ s->req_body_size = req_body_size;
+
+ struct ts_rpc_req_hdr *rpc_hdr = (struct ts_rpc_req_hdr *)s->req_body_buf;
+
+ rpc_hdr->encoding = s->rpc_caller.encoding;
+ rpc_hdr->param_len = req_len;
+
+ } else {
+ EMSG("Out of memory");
+ }
+ }
+
+ return handle;
+}
+
+static rpc_status_t call_invoke(void *context, const rpc_call_handle handle, uint32_t opcode,
+ rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ struct http_caller *s = (struct http_caller *)context;
+
+ *resp_len = 0;
+
+ if ((handle == s) && s->req_body_buf) {
+ struct ts_rpc_req_hdr *rpc_hdr = (struct ts_rpc_req_hdr *)s->req_body_buf;
+ struct payload_buffer request_buf = { 0 };
+ struct payload_buffer response_buf = { 0 };
+
+ rpc_status = TS_RPC_ERROR_EP_DOES_NOT_EXIT;
+
+ rpc_hdr->opcode = opcode;
+
+ request_buf.data = s->req_body_buf;
+ request_buf.size = s->req_body_size;
+
+ char call_url[HTTP_CALLER_MAX_URL_LEN];
+
+ prepare_call_url(s, opcode, call_url, sizeof(call_url));
+
+ if (send_put_request(call_url, &request_buf, &response_buf) && response_buf.data &&
+ response_buf.size >= sizeof(struct ts_rpc_resp_hdr)) {
+ struct ts_rpc_resp_hdr *resp_hdr =
+ (struct ts_rpc_resp_hdr *)response_buf.data;
+ size_t response_param_len =
+ response_buf.size - sizeof(struct ts_rpc_resp_hdr);
+
+ if (resp_hdr->param_len == response_param_len) {
+ rpc_status = resp_hdr->rpc_status;
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ *resp_buf =
+ &response_buf.data[sizeof(struct ts_rpc_resp_hdr)];
+ *resp_len = response_param_len;
+
+ *opstatus = resp_hdr->op_status;
+ }
+
+ } else {
+ rpc_status = TS_RPC_ERROR_INVALID_RESP_BODY;
+ }
+ }
+ }
+
+ return rpc_status;
+}
+
+static void call_end(void *context, const rpc_call_handle handle)
+{
+ struct http_caller *s = (struct http_caller *)context;
+
+ if ((handle == s) && s->req_body_buf) {
+ free(s->req_body_buf);
+ s->req_body_buf = NULL;
+
+ free(s->resp_body_buf);
+ s->resp_body_buf = NULL;
+ }
+}
diff --git a/components/rpc/http/caller/http_caller.h b/components/rpc/http/caller/http_caller.h
new file mode 100644
index 000000000..ac3a336c5
--- /dev/null
+++ b/components/rpc/http/caller/http_caller.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HTTP_CALLER_H
+#define HTTP_CALLER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "rpc_caller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HTTP_CALLER_MAX_URL_LEN (2048)
+
+/*
+ * An RPC caller that makes call requests via a REST API 'call' endpoint
+ * that provides a generic way to call trusted service operations via HTTP.
+ * The fw-test-api supports a call endpoint with the path:
+ * /services/{servicename}/call/{opcode}. A call request body carries the
+ * rpc header defined in protocols/rpc/common/packed-c.header.h, followed by
+ * serialized call parameters. A call response body carries the response header
+ * defined in the same file, followed by any serialized response parameters.
+ */
+struct http_caller {
+ struct rpc_caller rpc_caller;
+ char rpc_call_url[HTTP_CALLER_MAX_URL_LEN];
+ size_t req_body_size;
+ uint8_t *req_body_buf;
+ uint8_t *resp_body_buf;
+};
+
+struct rpc_caller *http_caller_init(struct http_caller *s);
+void http_caller_deinit(struct http_caller *s);
+
+bool http_caller_probe(const char *url, long *http_code);
+
+int http_caller_open(struct http_caller *s, const char *rpc_call_url);
+int http_caller_close(struct http_caller *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HTTP_CALLER_H */
diff --git a/components/rpc/http/caller/test/component.cmake b/components/rpc/http/caller/test/component.cmake
new file mode 100644
index 000000000..c55f0fca1
--- /dev/null
+++ b/components/rpc/http/caller/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/http_caller_tests.cpp"
+ )
diff --git a/components/rpc/http/caller/test/http_caller_tests.cpp b/components/rpc/http/caller/test/http_caller_tests.cpp
new file mode 100644
index 000000000..cfbc52a92
--- /dev/null
+++ b/components/rpc/http/caller/test/http_caller_tests.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+
+#include "protocols/rpc/common/packed-c/status.h"
+#include "protocols/service/discovery/packed-c/opcodes.h"
+#include "psa/error.h"
+#include "rpc/http/caller/http_caller.h"
+#include "service/locator/remote/restapi/restapi_location.h"
+
+/*
+ * http_caller tests rely on a fw test api server running on the local host
+ */
+TEST_GROUP(RpcCallerTests)
+{
+ void setup()
+ {
+ rpc_caller = http_caller_init(&http_caller_under_test);
+ CHECK_TRUE(rpc_caller);
+ }
+
+ void teardown()
+ {
+ http_caller_deinit(&http_caller_under_test);
+ }
+
+ http_caller http_caller_under_test;
+ struct rpc_caller *rpc_caller;
+};
+
+TEST(RpcCallerTests, probeAvailableHttpEndpoint)
+{
+ long http_code = 0;
+
+ CHECK_TRUE(http_caller_probe(RESTAPI_LOCATOR_API_URL, &http_code));
+ LONGS_EQUAL(200, http_code);
+}
+
+TEST(RpcCallerTests, probeUnavailableHost)
+{
+ long http_code = 0;
+
+ CHECK_FALSE(http_caller_probe("http://127.0.0.1:5001/", &http_code));
+ LONGS_EQUAL(0, http_code);
+}
+
+TEST(RpcCallerTests, callUnavailableApiEndpoint)
+{
+ int status;
+
+ status = http_caller_open(&http_caller_under_test, RESTAPI_LOCATOR_API_URL "foo/call/");
+ LONGS_EQUAL(0, status);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf = NULL;
+
+ call_handle = rpc_caller_begin(rpc_caller, &req_buf, 48);
+ CHECK_TRUE(call_handle);
+ CHECK_TRUE(req_buf);
+
+ rpc_status_t rpc_status;
+ rpc_opstatus_t op_status;
+ uint8_t *resp_buf = NULL;
+ size_t resp_len = 0;
+
+ rpc_status =
+ rpc_caller_invoke(rpc_caller, call_handle, 251, &op_status, &resp_buf, &resp_len);
+ LONGS_EQUAL(TS_RPC_ERROR_EP_DOES_NOT_EXIT, rpc_status);
+
+ rpc_caller_end(rpc_caller, call_handle);
+}
+
+TEST(RpcCallerTests, callAvailableApiEndpoint)
+{
+ int status;
+
+ status = http_caller_open(&http_caller_under_test, RESTAPI_LOCATOR_API_URL "fwu/call/");
+ LONGS_EQUAL(0, status);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf = NULL;
+
+ call_handle = rpc_caller_begin(rpc_caller, &req_buf, 48);
+ CHECK_TRUE(call_handle);
+ CHECK_TRUE(req_buf);
+
+ rpc_status_t rpc_status;
+ rpc_opstatus_t op_status;
+ uint8_t *resp_buf = NULL;
+ size_t resp_len = 0;
+
+ rpc_status = rpc_caller_invoke(rpc_caller, call_handle,
+ TS_DISCOVERY_OPCODE_GET_SERVICE_INFO, &op_status, &resp_buf,
+ &resp_len);
+ LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
+ LONGS_EQUAL(PSA_SUCCESS, op_status);
+ CHECK_TRUE(resp_len > 0);
+
+ rpc_caller_end(rpc_caller, call_handle);
+}
diff --git a/components/rpc/mm_communicate/caller/linux/carveout.c b/components/rpc/mm_communicate/caller/linux/carveout.c
index e3cdf16fe..fb389b41b 100644
--- a/components/rpc/mm_communicate/caller/linux/carveout.c
+++ b/components/rpc/mm_communicate/caller/linux/carveout.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,9 +11,12 @@
#include <fcntl.h>
#include "carveout.h"
-/* Need to be aligned with carve-out used by StMM or smm-gateway. */
-static const off_t carveout_pa = 0x0000000881000000;
-static const size_t carveout_len = 0x8000;
+#ifndef MM_COMM_BUFFER_ADDRESS
+#error "MM_COMM_BUFFER_ADDRESS macro is undefined!"
+#endif
+#ifndef MM_COMM_BUFFER_SIZE
+#error "MM_COMM_BUFFER_SIZE macro is undefined!"
+#endif
int carveout_claim(uint8_t **buf, size_t *buf_size)
{
@@ -22,14 +25,14 @@ int carveout_claim(uint8_t **buf, size_t *buf_size)
if (fd >= 0) {
- uint8_t *mem = mmap(NULL, carveout_len,
+ uint8_t *mem = mmap(NULL, (size_t)(MM_COMM_BUFFER_SIZE),
PROT_READ | PROT_WRITE, MAP_SHARED,
- fd, carveout_pa);
+ fd, (off_t)(MM_COMM_BUFFER_ADDRESS));
if (mem != MAP_FAILED) {
*buf = mem;
- *buf_size = carveout_len;
+ *buf_size = (size_t)(MM_COMM_BUFFER_SIZE);
status = 0;
}
diff --git a/components/rpc/mm_communicate/caller/linux/component.cmake b/components/rpc/mm_communicate/caller/linux/component.cmake
index 9435599b5..d670cf55a 100644
--- a/components/rpc/mm_communicate/caller/linux/component.cmake
+++ b/components/rpc/mm_communicate/caller/linux/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -10,6 +10,14 @@ endif()
include(${TS_ROOT}/external/LinuxFFAUserShim/LinuxFFAUserShim.cmake)
+if(NOT MM_COMM_BUFFER_ADDRESS OR NOT MM_COMM_BUFFER_SIZE)
+ message(FATAL_ERROR "Address and size of MM comm buffer is not set. Define MM_COMM_BUFFER_ADDRESS "
+ "and MM_COMM_BUFFER_SIZE.")
+endif()
+
+target_compile_definitions(${TGT} PRIVATE MM_COMM_BUFFER_ADDRESS=${MM_COMM_BUFFER_ADDRESS}
+ MM_COMM_BUFFER_SIZE=${MM_COMM_BUFFER_SIZE})
+
target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/mm_communicate_caller.c"
"${CMAKE_CURRENT_LIST_DIR}/mm_communicate_serializer.c"
diff --git a/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.c b/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.c
index dda796af3..676161632 100644
--- a/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.c
+++ b/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.c
@@ -1,11 +1,12 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "mm_communicate_caller.h"
#include "carveout.h"
+#include "util.h"
#include <arm_ffa_user.h>
#include <components/rpc/mm_communicate/common/mm_communicate_call_args.h>
#include <protocols/rpc/common/packed-c/status.h>
@@ -19,356 +20,416 @@
#include <string.h>
#include <errno.h>
-#define KERNEL_MOD_REQ_VER_MAJOR 2
+#define KERNEL_MOD_REQ_VER_MAJOR 5
#define KERNEL_MOD_REQ_VER_MINOR 0
#define KERNEL_MOD_REQ_VER_PATCH 0
-static rpc_call_handle call_begin(
- void *context,
- uint8_t **req_buf,
- size_t req_len);
+struct mm_communicate_caller_context {
+ int ffa_fd;
+ const char *ffa_device_path;
+ uint16_t dest_partition_id;
+ uint8_t *comm_buffer;
+ size_t comm_buffer_size;
+ size_t req_len;
+ const struct mm_communicate_serializer *serializer;
+};
-static rpc_status_t call_invoke(
- void *context,
- rpc_call_handle handle,
- uint32_t opcode,
- rpc_opstatus_t *opstatus,
- uint8_t **resp_buf,
- size_t *resp_len);
+static const char mm_uuid[] = "ed32d533-99e6-4209-9cc0-2d72cdd998a7";
-static void call_end(
- void *context,
- rpc_call_handle handle);
+static rpc_status_t release_shared_memory(void *context,
+ struct rpc_caller_shared_memory *shared_memory);
-static rpc_status_t mm_return_code_to_rpc_status(
- int32_t return_code);
-
-bool mm_communicate_caller_check_version(void)
+static void rpc_uuid_to_efi_guid(const struct rpc_uuid *uuid, EFI_GUID *guid)
{
- FILE *f;
- char mod_name[64];
- int ver_major, ver_minor, ver_patch;
- bool mod_loaded = false;
+ guid->Data1 = uuid->uuid[0] << 24 | uuid->uuid[1] << 16 | uuid->uuid[2] << 8 |
+ uuid->uuid[3];
+ guid->Data2 = uuid->uuid[4] << 8 | uuid->uuid[5];
+ guid->Data3 = uuid->uuid[6] << 8 | uuid->uuid[7];
+ memcpy(guid->Data4, &uuid->uuid[8], sizeof(guid->Data4));
+}
- f = fopen("/proc/modules", "r");
- if (!f) {
- printf("error: cannot open /proc/modules\n");
- return false;
+static rpc_status_t mm_return_code_to_rpc_status(int32_t return_code)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ switch (return_code) {
+ case MM_RETURN_CODE_NOT_SUPPORTED:
+ rpc_status = RPC_ERROR_NOT_FOUND;
+ break;
+ case MM_RETURN_CODE_INVALID_PARAMETER:
+ rpc_status = RPC_ERROR_INVALID_VALUE;
+ break;
+ case MM_RETURN_CODE_DENIED:
+ rpc_status = RPC_ERROR_INVALID_STATE;
+ break;
+ case MM_RETURN_CODE_NO_MEMORY:
+ rpc_status = RPC_ERROR_INTERNAL;
+ break;
+ default:
+ break;
}
- while (fscanf(f, "%64s %*[^\n]\n", mod_name) != EOF) {
- if (!strcmp(mod_name, "arm_ffa_user")) {
- mod_loaded = true;
- break;
- }
- }
+ return rpc_status;
+}
- fclose(f);
+static rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id)
+{
+ struct mm_communicate_caller_context *mm_context =
+ (struct mm_communicate_caller_context *)context;
+ EFI_GUID svc_guid = { 0 };
- if (!mod_loaded) {
- printf("error: kernel module not loaded\n");
- return false;
- }
+ if (!context || !service_uuid)
+ return RPC_ERROR_INVALID_VALUE;
- f = fopen("/sys/module/arm_ffa_user/version", "r");
- if (f) {
- fscanf(f, "%d.%d.%d", &ver_major, &ver_minor, &ver_patch);
- fclose(f);
- } else {
- /*
- * Fallback for the initial release of the kernel module, where
- * the version definition was missing.
- */
- ver_major = 1;
- ver_minor = 0;
- ver_patch = 0;
- }
+ if (mm_context->ffa_fd >= 0)
+ return RPC_ERROR_INVALID_STATE;
- if (ver_major != KERNEL_MOD_REQ_VER_MAJOR)
- goto err;
+ rpc_uuid_to_efi_guid(service_uuid, &svc_guid);
- if (ver_minor < KERNEL_MOD_REQ_VER_MINOR)
- goto err;
+ mm_context->serializer = mm_communicate_serializer_find(&svc_guid);
+ if (!mm_context->serializer)
+ return RPC_ERROR_INTERNAL;
- if (ver_minor == KERNEL_MOD_REQ_VER_MINOR)
- if (ver_patch < KERNEL_MOD_REQ_VER_PATCH)
- goto err;
+ if (!mm_context->ffa_device_path) {
+ mm_context->serializer = NULL;
+ return RPC_ERROR_INTERNAL;
+ }
- return true;
+ mm_context->ffa_fd = open(mm_context->ffa_device_path, O_RDWR);
+ if (mm_context->ffa_fd < 0) {
+ mm_context->serializer = NULL;
+ return RPC_ERROR_INTERNAL;
+ }
-err:
- printf("error: kernel module is v%d.%d.%d but required v%d.%d.%d\n",
- ver_major, ver_minor, ver_patch, KERNEL_MOD_REQ_VER_MAJOR,
- KERNEL_MOD_REQ_VER_MINOR, KERNEL_MOD_REQ_VER_PATCH);
+ mm_context->dest_partition_id = endpoint_id;
- return false;
+ return RPC_SUCCESS;
}
-struct rpc_caller *mm_communicate_caller_init(
- struct mm_communicate_caller *s,
- const char *ffa_device_path)
+static rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid)
{
- struct rpc_caller *base = &s->rpc_caller;
-
- rpc_caller_init(base, s);
- base->call_begin = call_begin;
- base->call_invoke = call_invoke;
- base->call_end = call_end;
-
- s->ffa_fd = -1;
- s->ffa_device_path = ffa_device_path;
- s->dest_partition_id = 0;
- s->comm_buffer = NULL;
- s->comm_buffer_size = 0;
- s->scrub_len = 0;
- s->req_len = 0;
- s->is_call_transaction_in_progess = false;
- s->serializer = NULL;
-
- return base;
-}
+ struct mm_communicate_caller_context *mm_context =
+ (struct mm_communicate_caller_context *)context;
+ int fd = 0;
+ int status = 0;
+ struct ffa_ioctl_ep_desc discovered_partition = { 0 };
-void mm_communicate_caller_deinit(
- struct mm_communicate_caller *s)
-{
- s->rpc_caller.context = NULL;
- s->rpc_caller.call_begin = NULL;
- s->rpc_caller.call_invoke = NULL;
- s->rpc_caller.call_end = NULL;
+ if (!context || !service_uuid)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (mm_context->ffa_fd >= 0)
+ return RPC_ERROR_INVALID_STATE;
+
+ if (!mm_context->ffa_device_path)
+ return RPC_ERROR_INTERNAL;
+
+ fd = open(mm_context->ffa_device_path, O_RDWR);
+ if (fd < 0)
+ return RPC_ERROR_INTERNAL;
- call_end(s, s);
- mm_communicate_caller_close(s);
+ discovered_partition.uuid_ptr = (uintptr_t)&mm_uuid;
+ discovered_partition.id = 0;
+
+ status = ioctl(fd, FFA_IOC_GET_PART_ID, &discovered_partition);
+ if (status < 0) {
+ close(fd);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ status = close(fd);
+ if (status < 0)
+ return RPC_ERROR_INTERNAL;
+
+ return open_session(context, service_uuid, discovered_partition.id);
}
-size_t mm_communicate_caller_discover(
- const struct mm_communicate_caller *s,
- const struct uuid_canonical *uuid,
- uint16_t *partition_ids,
- size_t discover_limit)
+static rpc_status_t close_session(void *context)
{
- size_t discover_count = 0;
+ struct mm_communicate_caller_context *mm_context =
+ (struct mm_communicate_caller_context *)context;
+ int status = -1;
- if (uuid && partition_ids && s->ffa_device_path) {
- int fd;
+ if (!context)
+ return RPC_ERROR_INVALID_VALUE;
- fd = open(s->ffa_device_path, O_RDWR);
+ if (mm_context->ffa_fd < 0)
+ return RPC_ERROR_INVALID_STATE;
- if (fd >= 0) {
- int ioctl_status;
- struct ffa_ioctl_ep_desc discovered_partition;
+ if (mm_context->comm_buffer) {
+ struct rpc_caller_shared_memory memory = { 0 };
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
- discovered_partition.uuid_ptr = (uintptr_t)&uuid->characters;
- discovered_partition.id = 0;
+ memory.id = 0;
+ memory.buffer = mm_context->comm_buffer;
+ memory.size = mm_context->comm_buffer_size;
- ioctl_status = ioctl(fd, FFA_IOC_GET_PART_ID, &discovered_partition);
+ rpc_status = release_shared_memory(context, &memory);
+ if (rpc_status != RPC_SUCCESS)
+ return rpc_status;
+ }
- if ((ioctl_status == 0) && (discover_count < discover_limit)) {
- partition_ids[discover_count] = discovered_partition.id;
- ++discover_count;
- }
+ status = close(mm_context->ffa_fd);
+ if (status < 0)
+ return RPC_ERROR_INTERNAL;
- close(fd);
- }
- }
+ mm_context->ffa_fd = -1;
+ mm_context->dest_partition_id = 0;
+ mm_context->serializer = NULL;
- return discover_count;
+ return RPC_SUCCESS;
}
-int mm_communicate_caller_open(
- struct mm_communicate_caller *s,
- uint16_t dest_partition_id,
- const EFI_GUID *svc_guid)
+static bool is_valid_shared_memory(const struct mm_communicate_caller_context *mm_context,
+ const struct rpc_caller_shared_memory *shared_memory)
{
- int status = -1;
+ uintptr_t comm_buffer_end = 0;
+ uintptr_t shared_memory_end = 0;
- s->serializer = mm_communicate_serializer_find(svc_guid);
+ if (ADD_OVERFLOW((uintptr_t)mm_context->comm_buffer,
+ (uintptr_t)mm_context->comm_buffer_size, &comm_buffer_end))
+ return false;
+
+ if (ADD_OVERFLOW((uintptr_t)shared_memory->buffer, (uintptr_t)shared_memory->size,
+ &shared_memory_end))
+ return false;
+
+ return (uintptr_t)mm_context->comm_buffer <= (uintptr_t)shared_memory->buffer &&
+ shared_memory_end <= comm_buffer_end;
+}
- if (s->serializer && s->ffa_device_path) {
+static rpc_status_t create_shared_memory(void *context, size_t size,
+ struct rpc_caller_shared_memory *shared_memory)
+{
+ struct mm_communicate_caller_context *mm_context =
+ (struct mm_communicate_caller_context *)context;
+ size_t hdr_size = 0;
+ size_t required_size = 0;
+ int status = -1;
- s->ffa_fd = open(s->ffa_device_path, O_RDWR);
+ if (!context || !shared_memory)
+ return RPC_ERROR_INVALID_VALUE;
- if ((s->ffa_fd >= 0) && !s->comm_buffer) {
+ *shared_memory = (struct rpc_caller_shared_memory){ 0 };
- status = carveout_claim(
- &s->comm_buffer,
- &s->comm_buffer_size);
+ if (!mm_context->serializer || mm_context->comm_buffer)
+ return RPC_ERROR_INVALID_STATE;
- if (status == 0) {
+ hdr_size = mm_communicate_serializer_header_size(mm_context->serializer);
+ if (!hdr_size)
+ return RPC_ERROR_INTERNAL;
- s->dest_partition_id = dest_partition_id;
- }
- else {
- /* Failed to claim carveout */
- s->comm_buffer = NULL;
- s->comm_buffer_size = 0;
+ status = carveout_claim(&mm_context->comm_buffer, &mm_context->comm_buffer_size);
+ if (status) {
+ mm_context->comm_buffer = NULL;
+ mm_context->comm_buffer_size = 0;
- mm_communicate_caller_close(s);
- }
- }
+ return RPC_ERROR_INTERNAL;
}
- if (status != 0) {
+ if (ADD_OVERFLOW(hdr_size, size, &required_size) ||
+ required_size > mm_context->comm_buffer_size) {
+ carveout_relinquish(mm_context->comm_buffer, mm_context->comm_buffer_size);
+ mm_context->comm_buffer = NULL;
+ mm_context->comm_buffer_size = 0;
- s->serializer = NULL;
+ return RPC_ERROR_INVALID_VALUE;
}
- return status;
+ shared_memory->id = 0;
+ shared_memory->buffer = &mm_context->comm_buffer[hdr_size];
+ shared_memory->size = mm_context->comm_buffer_size - hdr_size;
+
+ return RPC_SUCCESS;
}
-int mm_communicate_caller_close(
- struct mm_communicate_caller *s)
+static rpc_status_t release_shared_memory(void *context,
+ struct rpc_caller_shared_memory *shared_memory)
{
- if (s->ffa_fd >= 0) {
+ struct mm_communicate_caller_context *mm_context =
+ (struct mm_communicate_caller_context *)context;
- close(s->ffa_fd);
- s->ffa_fd = -1;
- s->dest_partition_id = 0;
- }
+ if (!context || !shared_memory)
+ return RPC_ERROR_INVALID_VALUE;
- if (s->comm_buffer) {
+ if (!mm_context->comm_buffer)
+ return RPC_ERROR_INVALID_STATE;
- carveout_relinquish(s->comm_buffer, s->comm_buffer_size);
- s->comm_buffer = NULL;
- s->comm_buffer_size = 0;
- }
+ if (!is_valid_shared_memory(mm_context, shared_memory))
+ return RPC_ERROR_INVALID_VALUE;
- s->serializer = NULL;
+ memset(mm_context->comm_buffer, 0x00, mm_context->comm_buffer_size);
- s->is_call_transaction_in_progess = false;
+ carveout_relinquish(mm_context->comm_buffer, mm_context->comm_buffer_size);
+ mm_context->comm_buffer = NULL;
+ mm_context->comm_buffer_size = 0;
- return ((s->ffa_fd < 0) && !s->comm_buffer) ? 0 : -1;
+ return RPC_SUCCESS;
}
-static rpc_call_handle call_begin(
- void *context,
- uint8_t **req_buf,
- size_t req_len)
+static rpc_status_t call(void *context, uint16_t opcode,
+ struct rpc_caller_shared_memory *shared_memory, size_t request_length,
+ size_t *response_length, service_status_t *service_status)
{
- rpc_call_handle handle = NULL;
- struct mm_communicate_caller *s = (struct mm_communicate_caller*)context;
- size_t hdr_size = mm_communicate_serializer_header_size(s->serializer);
- *req_buf = NULL;
+ struct mm_communicate_caller_context *mm_context =
+ (struct mm_communicate_caller_context *)context;
+ struct ffa_ioctl_msg_args direct_msg = { 0 };
+ int kernel_op_status = 0;
+ int32_t mm_return_code = 0;
+ uint8_t *resp_buf = NULL;
- if (!s->is_call_transaction_in_progess && hdr_size) {
+ if (!context || !shared_memory || !response_length || !service_status)
+ return RPC_ERROR_INVALID_VALUE;
- if (req_len + hdr_size <= s->comm_buffer_size) {
+ if (!is_valid_shared_memory(mm_context, shared_memory))
+ return RPC_ERROR_INVALID_VALUE;
- s->is_call_transaction_in_progess = true;
- handle = s;
+ mm_communicate_serializer_header_encode(mm_context->serializer, mm_context->comm_buffer,
+ opcode, request_length);
- s->req_len = req_len;
- *req_buf = &s->comm_buffer[hdr_size];
+ /* Make direct call to send the request */
+ direct_msg.dst_id = mm_context->dest_partition_id;
+ direct_msg.args[MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_OFFSET] = 0;
- s->scrub_len = hdr_size + req_len;
- }
- else {
+ kernel_op_status = ioctl(mm_context->ffa_fd, FFA_IOC_MSG_SEND, &direct_msg);
+ if (kernel_op_status < 0)
+ return RPC_ERROR_INTERNAL;
- s->req_len = 0;
- }
- }
-
- return handle;
-}
+ /* Kernel send operation completed normally */
+ mm_return_code = direct_msg.args[MM_COMMUNICATE_CALL_ARGS_RETURN_CODE];
+ if (mm_return_code != MM_RETURN_CODE_SUCCESS)
+ return mm_return_code_to_rpc_status(mm_return_code);
-static rpc_status_t call_invoke(
- void *context,
- rpc_call_handle handle,
- uint32_t opcode,
- rpc_opstatus_t *opstatus,
- uint8_t **resp_buf,
- size_t *resp_len)
-{
- struct mm_communicate_caller *s = (struct mm_communicate_caller*)context;
+ mm_communicate_serializer_header_decode(mm_context->serializer, mm_context->comm_buffer,
+ (efi_status_t *)service_status, &resp_buf,
+ response_length);
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- *resp_len = 0;
+ if (resp_buf != shared_memory->buffer)
+ return RPC_ERROR_INVALID_RESPONSE_BODY;
- if ((handle == s) && s->is_call_transaction_in_progess) {
-
- mm_communicate_serializer_header_encode(s->serializer,
- s->comm_buffer, opcode, s->req_len);
-
- /* Make direct call to send the request */
- struct ffa_ioctl_msg_args direct_msg;
- memset(&direct_msg, 0, sizeof(direct_msg));
+ return RPC_SUCCESS;
+}
- direct_msg.dst_id = s->dest_partition_id;
+static bool mm_communicate_caller_check_version(void)
+{
+ FILE *f = NULL;
+ char mod_name[64] = { 0 };
+ int ver_major = 0, ver_minor = 0, ver_patch = 0;
+ bool mod_loaded = false;
- direct_msg.args[MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_ADDRESS] = (uintptr_t)s->comm_buffer;
- direct_msg.args[MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_SIZE] = s->comm_buffer_size;
+ f = fopen("/proc/modules", "r");
+ if (!f) {
+ printf("error: cannot open /proc/modules\n");
+ return false;
+ }
- int kernel_op_status = ioctl(s->ffa_fd, FFA_IOC_MSG_SEND, &direct_msg);
+ while (fscanf(f, "%63s %*[^\n]\n", mod_name) != EOF) {
+ if (!strcmp(mod_name, "arm_ffa_user")) {
+ mod_loaded = true;
+ break;
+ }
+ }
- if (kernel_op_status == 0) {
+ fclose(f);
- /* Kernel send operation completed normally */
- uint32_t mm_return_id = direct_msg.args[MM_COMMUNICATE_CALL_ARGS_RETURN_ID];
- int32_t mm_return_code = direct_msg.args[MM_COMMUNICATE_CALL_ARGS_RETURN_CODE];
+ if (!mod_loaded) {
+ printf("error: kernel module not loaded\n");
+ return false;
+ }
- if (mm_return_id == ARM_SVC_ID_SP_EVENT_COMPLETE) {
+ f = fopen("/sys/module/arm_ffa_user/version", "r");
+ if (f) {
+ fscanf(f, "%d.%d.%d", &ver_major, &ver_minor, &ver_patch);
+ fclose(f);
+ } else {
+ /*
+ * Fallback for the initial release of the kernel module, where
+ * the version definition was missing.
+ */
+ ver_major = 1;
+ ver_minor = 0;
+ ver_patch = 0;
+ }
- if (mm_return_code == MM_RETURN_CODE_SUCCESS) {
+ if (ver_major != KERNEL_MOD_REQ_VER_MAJOR)
+ goto err;
- mm_communicate_serializer_header_decode(s->serializer,
- s->comm_buffer, opstatus, resp_buf, resp_len);
+ if (ver_minor < KERNEL_MOD_REQ_VER_MINOR)
+ goto err;
- if (*resp_len > s->req_len) {
+ if (ver_minor == KERNEL_MOD_REQ_VER_MINOR)
+ if (ver_patch < KERNEL_MOD_REQ_VER_PATCH)
+ goto err;
- s->scrub_len =
- mm_communicate_serializer_header_size(s->serializer) +
- *resp_len;
- }
+ return true;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- else {
+err:
+ printf("error: kernel module is v%d.%d.%d but required v%d.%d.%d\n", ver_major, ver_minor,
+ ver_patch, KERNEL_MOD_REQ_VER_MAJOR, KERNEL_MOD_REQ_VER_MINOR,
+ KERNEL_MOD_REQ_VER_PATCH);
- rpc_status = mm_return_code_to_rpc_status(mm_return_code);
- }
- }
- }
- }
+ return false;
+}
- return rpc_status;
+rpc_status_t mm_communicate_caller_init(struct rpc_caller_interface *rpc_caller,
+ const char *ffa_device_path)
+{
+ struct mm_communicate_caller_context *context = NULL;
+
+ if (!rpc_caller || !ffa_device_path)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (!mm_communicate_caller_check_version())
+ return RPC_ERROR_INTERNAL;
+
+ context = (struct mm_communicate_caller_context *)calloc(
+ 1, sizeof(struct mm_communicate_caller_context));
+ if (!context)
+ return RPC_ERROR_INTERNAL;
+
+ context->ffa_fd = -1;
+ context->ffa_device_path = ffa_device_path;
+ context->dest_partition_id = 0;
+ context->comm_buffer = NULL;
+ context->comm_buffer_size = 0;
+ context->req_len = 0;
+ context->serializer = NULL;
+
+ rpc_caller->context = context;
+ rpc_caller->open_session = open_session;
+ rpc_caller->find_and_open_session = find_and_open_session;
+ rpc_caller->close_session = close_session;
+ rpc_caller->create_shared_memory = create_shared_memory;
+ rpc_caller->release_shared_memory = release_shared_memory;
+ rpc_caller->call = call;
+
+ return RPC_SUCCESS;
}
-static void call_end(void *context, rpc_call_handle handle)
+rpc_status_t mm_communicate_caller_deinit(struct rpc_caller_interface *rpc_caller)
{
- struct mm_communicate_caller *s = (struct mm_communicate_caller*)context;
+ struct mm_communicate_caller_context *mm_context = NULL;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
- if ((handle == s) && s->is_call_transaction_in_progess) {
+ if (!rpc_caller || !rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
- /* Call transaction complete */
- s->req_len = 0;
- s->is_call_transaction_in_progess = false;
+ mm_context = (struct mm_communicate_caller_context *)rpc_caller->context;
- /* Scrub the comms buffer */
- memset(s->comm_buffer, 0, s->scrub_len);
- s->scrub_len = 0;
+ if (mm_context->comm_buffer) {
+ carveout_relinquish(mm_context->comm_buffer, mm_context->comm_buffer_size);
+ mm_context->comm_buffer = NULL;
+ mm_context->comm_buffer_size = 0;
}
-}
-static rpc_status_t mm_return_code_to_rpc_status(int32_t return_code)
-{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
-
- switch (return_code)
- {
- case MM_RETURN_CODE_NOT_SUPPORTED:
- rpc_status = TS_RPC_ERROR_INTERFACE_DOES_NOT_EXIST;
- break;
- case MM_RETURN_CODE_INVALID_PARAMETER:
- rpc_status = TS_RPC_ERROR_INVALID_PARAMETER;
- break;
- case MM_RETURN_CODE_DENIED:
- rpc_status = TS_RPC_ERROR_ACCESS_DENIED;
- break;
- case MM_RETURN_CODE_NO_MEMORY:
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- break;
- default:
- break;
+ if (mm_context->ffa_fd >= 0) {
+ status = rpc_caller_close_session(rpc_caller);
+ if (status != RPC_SUCCESS)
+ return status;
}
- return rpc_status;
+ free(rpc_caller->context);
+ rpc_caller->context = NULL;
+
+ return RPC_SUCCESS;
}
diff --git a/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h b/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h
index 842068151..d1a2c5cf3 100644
--- a/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h
+++ b/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h
@@ -10,10 +10,9 @@
#include <stdbool.h>
#include <common/uuid/uuid.h>
#include <protocols/common/efi/efi_types.h>
-#include <rpc_caller.h>
+#include "rpc_caller.h"
#include "mm_communicate_serializer.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -22,42 +21,12 @@ extern "C" {
* An RPC caller for Linux user-space clients that uses the MM_COMMUNICATE
* protocol for calling UEFI SMM service endpoints.
*/
-struct mm_communicate_caller
-{
- struct rpc_caller rpc_caller;
- int ffa_fd;
- const char *ffa_device_path;
- uint16_t dest_partition_id;
- uint8_t *comm_buffer;
- size_t comm_buffer_size;
- size_t req_len;
- size_t scrub_len;
- bool is_call_transaction_in_progess;
- const struct mm_communicate_serializer *serializer;
-};
-
-bool mm_communicate_caller_check_version(void);
-
-struct rpc_caller *mm_communicate_caller_init(
- struct mm_communicate_caller *s,
- const char *ffa_device_path);
-
-void mm_communicate_caller_deinit(
- struct mm_communicate_caller *s);
-
-size_t mm_communicate_caller_discover(
- const struct mm_communicate_caller *s,
- const struct uuid_canonical *uuid,
- uint16_t *partition_ids,
- size_t discover_limit);
-
-int mm_communicate_caller_open(
- struct mm_communicate_caller *s,
- uint16_t dest_partition_id,
- const EFI_GUID *svc_guid);
+RPC_CALLER_EXPORTED
+rpc_status_t mm_communicate_caller_init(struct rpc_caller_interface *caller,
+ const char *ffa_device_path);
-int mm_communicate_caller_close(
- struct mm_communicate_caller *s);
+RPC_CALLER_EXPORTED
+rpc_status_t mm_communicate_caller_deinit(struct rpc_caller_interface *caller);
#ifdef __cplusplus
}
diff --git a/components/rpc/mm_communicate/common/mm_communicate_call_args.h b/components/rpc/mm_communicate/common/mm_communicate_call_args.h
index 7d7311daf..280c04d4d 100644
--- a/components/rpc/mm_communicate/common/mm_communicate_call_args.h
+++ b/components/rpc/mm_communicate/common/mm_communicate_call_args.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifndef MM_COMMUNICATE_CALL_ARGS_H_
@@ -12,13 +12,12 @@
*/
/* SP message arg indexes */
-#define MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_ADDRESS 0
-#define MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_SIZE 1
+#define MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_OFFSET 0
-#define MM_COMMUNICATE_CALL_ARGS_RETURN_ID 0
-#define MM_COMMUNICATE_CALL_ARGS_RETURN_CODE 1
-#define MM_COMMUNICATE_CALL_ARGS_MBZ0 2
-#define MM_COMMUNICATE_CALL_ARGS_MBZ1 3
-#define MM_COMMUNICATE_CALL_ARGS_MBZ2 4
+#define MM_COMMUNICATE_CALL_ARGS_RETURN_CODE 0
+#define MM_COMMUNICATE_CALL_ARGS_MBZ0 1
+#define MM_COMMUNICATE_CALL_ARGS_MBZ1 2
+#define MM_COMMUNICATE_CALL_ARGS_MBZ2 3
+#define MM_COMMUNICATE_CALL_ARGS_MBZ3 4
#endif /* MM_COMMUNICATE_CALL_ARGS_H_ */
diff --git a/components/rpc/mm_communicate/endpoint/sp/component.cmake b/components/rpc/mm_communicate/endpoint/sp/component.cmake
index 456b9a7e3..ca453cee6 100644
--- a/components/rpc/mm_communicate/endpoint/sp/component.cmake
+++ b/components/rpc/mm_communicate/endpoint/sp/component.cmake
@@ -11,3 +11,14 @@ endif()
target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/mm_communicate_call_ep.c"
)
+
+if(NOT ((TS_ENV STREQUAL "linux-pc") OR (TS_ENV STREQUAL "arm-linux")))
+ if(NOT DEFINED SP_BIN_UUID_CANON)
+ message(FATAL_ERROR "Mandatory parameter SP_BIN_UUID_CANON is not defined.")
+ endif()
+
+ # Verify that SP is using the TS protocol.
+ if ("${SP_FFA_UUID_CANON}" STREQUAL "${TS_RPC_UUID_CANON}")
+ message(FATAL_ERROR "The code is using MM RPC, but the SP_FFA_UUID_CANON is matching the TS RPC UUID.")
+ endif()
+endif() \ No newline at end of file
diff --git a/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c b/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c
index 09f1e2c56..42ca69878 100644
--- a/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c
+++ b/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#include "components/rpc/mm_communicate/common/mm_communicate_call_args.h"
@@ -15,6 +15,9 @@ bool mm_communicate_call_ep_init(struct mm_communicate_ep *call_ep, uint8_t *com
{
unsigned int i = 0;
+ if (!call_ep || !comm_buffer)
+ return false;
+
if (comm_buffer_size < EFI_MM_COMMUNICATE_HEADER_SIZE)
return false;
@@ -35,60 +38,62 @@ bool mm_communicate_call_ep_init(struct mm_communicate_ep *call_ep, uint8_t *com
static int32_t invoke_mm_service(struct mm_communicate_ep *call_ep, uint16_t source_id,
struct mm_service_interface *iface,
- EFI_MM_COMMUNICATE_HEADER *header)
+ EFI_MM_COMMUNICATE_HEADER *header,
+ size_t buffer_size)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
struct mm_service_call_req call_req = { 0 };
int32_t result = 0;
call_req.guid = &header->HeaderGuid;
- /*
- * The subtraction for size field should be overflow-safe because of the
- * check in the init funciton.
- */
call_req.req_buf.data = header->Data;
- call_req.req_buf.data_len = header->MessageLength;
- call_req.req_buf.size = call_ep->comm_buffer_size - EFI_MM_COMMUNICATE_HEADER_SIZE;
+ call_req.req_buf.data_length = header->MessageLength;
+ call_req.req_buf.size = buffer_size;
call_req.resp_buf.data = header->Data;
- call_req.resp_buf.data_len = 0;
- call_req.resp_buf.size = call_ep->comm_buffer_size - EFI_MM_COMMUNICATE_HEADER_SIZE;
+ call_req.resp_buf.data_length = 0;
+ call_req.resp_buf.size = buffer_size;
result = iface->receive(iface, &call_req);
- header->MessageLength = call_req.resp_buf.data_len;
+ header->MessageLength = call_req.resp_buf.data_length;
return result;
}
static int32_t handle_mm_communicate(struct mm_communicate_ep *call_ep, uint16_t source_id,
- uintptr_t buffer_addr, size_t buffer_size)
+ size_t buffer_offset)
{
- uintptr_t buffer_arg = 0;
- size_t request_size = 0;
+ size_t header_end_offset = 0;
+ size_t request_end_offset = 0;
+ size_t buffer_size = 0;
EFI_MM_COMMUNICATE_HEADER *header = NULL;
unsigned int i = 0;
- /* Validating call args according to ARM MM spec 3.2.4 */
- if (buffer_addr == 0)
+ if (ADD_OVERFLOW(buffer_offset, EFI_MM_COMMUNICATE_HEADER_SIZE, &header_end_offset))
+ return MM_RETURN_CODE_INVALID_PARAMETER;
+
+ if (call_ep->comm_buffer_size < header_end_offset)
return MM_RETURN_CODE_INVALID_PARAMETER;
/* Validating comm buffer contents */
- header = (EFI_MM_COMMUNICATE_HEADER *)call_ep->comm_buffer;
- if (ADD_OVERFLOW(header->MessageLength, EFI_MM_COMMUNICATE_HEADER_SIZE, &request_size))
+ header = (EFI_MM_COMMUNICATE_HEADER *)(call_ep->comm_buffer + buffer_offset);
+ if (ADD_OVERFLOW(header_end_offset, header->MessageLength, &request_end_offset))
return MM_RETURN_CODE_INVALID_PARAMETER;
- if (call_ep->comm_buffer_size < request_size)
+ if (call_ep->comm_buffer_size < request_end_offset)
return MM_RETURN_CODE_INVALID_PARAMETER;
+ buffer_size = call_ep->comm_buffer_size - header_end_offset;
+
/* Finding iface_id by GUID */
for (i = 0; i < ARRAY_SIZE(call_ep->service_table); i++) {
const struct mm_service_entry *entry = &call_ep->service_table[i];
if (entry->iface != NULL &&
memcmp(&header->HeaderGuid, &entry->guid, sizeof(entry->guid)) == 0)
- return invoke_mm_service(call_ep, source_id, entry->iface, header);
+ return invoke_mm_service(call_ep, source_id, entry->iface, header,
+ buffer_size);
}
return MM_RETURN_CODE_NOT_SUPPORTED;
@@ -123,19 +128,16 @@ void mm_communicate_call_ep_receive(struct mm_communicate_ep *mm_communicate_cal
const struct ffa_direct_msg *req_msg,
struct ffa_direct_msg *resp_msg)
{
- int32_t return_value = 0;
- uintptr_t buffer_address = 0;
- size_t buffer_size = 0;
-
- buffer_address = req_msg->args[MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_ADDRESS];
- buffer_size = req_msg->args[MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_SIZE];
-
- return_value = handle_mm_communicate(mm_communicate_call_ep, req_msg->source_id,
- buffer_address, buffer_size);
-
- resp_msg->args[MM_COMMUNICATE_CALL_ARGS_RETURN_ID] = ARM_SVC_ID_SP_EVENT_COMPLETE;
- resp_msg->args[MM_COMMUNICATE_CALL_ARGS_RETURN_CODE] = return_value;
- resp_msg->args[MM_COMMUNICATE_CALL_ARGS_MBZ0] = 0;
- resp_msg->args[MM_COMMUNICATE_CALL_ARGS_MBZ1] = 0;
- resp_msg->args[MM_COMMUNICATE_CALL_ARGS_MBZ2] = 0;
+ int32_t return_value = MM_RETURN_CODE_NOT_SUPPORTED;
+ size_t buffer_offset = req_msg->args.args64[MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_OFFSET];
+
+ return_value = handle_mm_communicate(mm_communicate_call_ep,
+ req_msg->source_id,
+ buffer_offset);
+
+ resp_msg->args.args64[MM_COMMUNICATE_CALL_ARGS_RETURN_CODE] = return_value;
+ resp_msg->args.args64[MM_COMMUNICATE_CALL_ARGS_MBZ0] = 0;
+ resp_msg->args.args64[MM_COMMUNICATE_CALL_ARGS_MBZ1] = 0;
+ resp_msg->args.args64[MM_COMMUNICATE_CALL_ARGS_MBZ2] = 0;
+ resp_msg->args.args64[MM_COMMUNICATE_CALL_ARGS_MBZ3] = 0;
}
diff --git a/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h b/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h
index 75d35152f..15a7e62e6 100644
--- a/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h
+++ b/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h
@@ -6,7 +6,7 @@
#ifndef MM_COMMUNICATE_CALL_EP_H_
#define MM_COMMUNICATE_CALL_EP_H_
-#include "components/rpc/common/endpoint/rpc_interface.h"
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include "protocols/common/efi/efi_types.h"
#include "ffa_api.h"
#include <stdbool.h>
@@ -26,8 +26,8 @@ extern "C" {
*/
struct mm_service_call_req {
EFI_GUID *guid;
- struct call_param_buf req_buf;
- struct call_param_buf resp_buf;
+ struct rpc_buffer req_buf;
+ struct rpc_buffer resp_buf;
};
/**
diff --git a/components/rpc/mm_communicate/endpoint/sp/test/mm_service_call_req_comparator.h b/components/rpc/mm_communicate/endpoint/sp/test/mm_service_call_req_comparator.h
index 438a5d4fd..4280cd15e 100644
--- a/components/rpc/mm_communicate/endpoint/sp/test/mm_service_call_req_comparator.h
+++ b/components/rpc/mm_communicate/endpoint/sp/test/mm_service_call_req_comparator.h
@@ -8,7 +8,7 @@
#include <CppUTestExt/MockSupport.h>
#include <string.h>
-#include "components/rpc/common/test/call_param_buf_comparator.h"
+#include "components/rpc/common/test/rpc_buffer_comparator.h"
#include "../mm_communicate_call_ep.h"
class mm_service_call_req_comparator : public MockNamedValueComparator
@@ -18,9 +18,9 @@ public:
{
struct mm_service_call_req *req1 = (struct mm_service_call_req *)object1;
struct mm_service_call_req *req2 = (struct mm_service_call_req *)object2;
- call_param_buf_comparator buf_comparator_normal;
- call_param_buf_comparator buf_comparator_ignore_data_len(
- call_param_buf_comparator::mode_ignore_data_len);
+ rpc_buffer_comparator buf_comparator_normal;
+ rpc_buffer_comparator buf_comparator_ignore_data_len(
+ rpc_buffer_comparator::mode_ignore_data_len);
return memcmp(req1->guid, req2->guid, sizeof(*req1->guid)) == 0 &&
buf_comparator_normal.isEqual(&req1->req_buf, &req2->req_buf) &&
@@ -31,9 +31,9 @@ public:
virtual SimpleString valueToString(const void *object)
{
struct mm_service_call_req *req = (struct mm_service_call_req *)object;
- call_param_buf_comparator buf_comparator_normal;
- call_param_buf_comparator buf_comparator_ignore_data_len(
- call_param_buf_comparator::mode_ignore_data_len);
+ rpc_buffer_comparator buf_comparator_normal;
+ rpc_buffer_comparator buf_comparator_ignore_data_len(
+ rpc_buffer_comparator::mode_ignore_data_len);
SimpleString req_buf_str = buf_comparator_normal.valueToString(&req->req_buf);
SimpleString resp_buf_str =
buf_comparator_ignore_data_len.valueToString(&req->resp_buf);
diff --git a/components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.cpp b/components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.cpp
index a58c33ab1..c8f38c7bc 100644
--- a/components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.cpp
+++ b/components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#include <CppUTestExt/MockSupport.h>
@@ -16,11 +16,11 @@ void mock_mm_service_init(void)
void expect_mock_mm_service_receive(struct mm_service_interface *iface,
const struct mm_service_call_req *req,
- int32_t result)
+ int64_t result)
{
mock().expectOneCall("mm_service_receive").onObject(iface).
- withOutputParameterReturning("resp_buf_data_len", &req->resp_buf.data_len,
- sizeof(req->resp_buf.data_len)).
+ withOutputParameterReturning("resp_buf_data_len", &req->resp_buf.data_length,
+ sizeof(req->resp_buf.data_length)).
withParameterOfType("mm_service_call_req", "req", req).
andReturnValue(result);
}
@@ -29,7 +29,7 @@ int32_t mock_mm_service_receive(struct mm_service_interface *iface,
struct mm_service_call_req *req)
{
return mock().actualCall("mm_service_receive").onObject(iface).
- withOutputParameter("resp_buf_data_len", &req->resp_buf.data_len).
+ withOutputParameter("resp_buf_data_len", &req->resp_buf.data_length).
withParameterOfType("mm_service_call_req", "req", req).
- returnIntValue();
+ returnLongIntValue();
}
diff --git a/components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.h b/components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.h
index 768022db8..56c8a264e 100644
--- a/components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.h
+++ b/components/rpc/mm_communicate/endpoint/sp/test/mock_mm_service.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifndef MOCK_MM_SERVICE_H_
@@ -16,7 +16,7 @@ void mock_mm_service_init(void);
void expect_mock_mm_service_receive(struct mm_service_interface *iface,
const struct mm_service_call_req *req,
- int32_t result);
+ int64_t result);
int32_t mock_mm_service_receive(struct mm_service_interface *iface,
struct mm_service_call_req *req);
diff --git a/components/rpc/mm_communicate/endpoint/sp/test/test_mm_communicate_call_ep.cpp b/components/rpc/mm_communicate/endpoint/sp/test/test_mm_communicate_call_ep.cpp
index 55a61fb7a..a21eca7e1 100644
--- a/components/rpc/mm_communicate/endpoint/sp/test/test_mm_communicate_call_ep.cpp
+++ b/components/rpc/mm_communicate/endpoint/sp/test/test_mm_communicate_call_ep.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#include <CppUTest/TestHarness.h>
@@ -32,14 +32,14 @@ TEST_GROUP(mm_communicate_call_ep)
mock().clear();
}
- void check_sp_msg(const struct ffa_direct_msg *msg, uint32_t arg0,
- uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4)
+ void check_sp_msg(const struct ffa_direct_msg *msg, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4)
{
- UNSIGNED_LONGLONGS_EQUAL(arg0, msg->args[0]);
- UNSIGNED_LONGLONGS_EQUAL(arg1, msg->args[1]);
- UNSIGNED_LONGLONGS_EQUAL(arg2, msg->args[2]);
- UNSIGNED_LONGLONGS_EQUAL(arg3, msg->args[3]);
- UNSIGNED_LONGLONGS_EQUAL(arg4, msg->args[4]);
+ UNSIGNED_LONGLONGS_EQUAL(arg0, msg->args.args64[0]);
+ UNSIGNED_LONGLONGS_EQUAL(arg1, msg->args.args64[1]);
+ UNSIGNED_LONGLONGS_EQUAL(arg2, msg->args.args64[2]);
+ UNSIGNED_LONGLONGS_EQUAL(arg3, msg->args.args64[3]);
+ UNSIGNED_LONGLONGS_EQUAL(arg4, msg->args.args64[4]);
}
struct mm_communicate_ep call_ep;
@@ -114,59 +114,54 @@ TEST(mm_communicate_call_ep, attach_do_not_fit)
}
}
-TEST(mm_communicate_call_ep, mm_communicate_no_buffer_arg)
+TEST(mm_communicate_call_ep, mm_communicate_offset_int_overflow)
{
CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
+ req_msg.args.args64[0] = 0xffffffffffffffff;
mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- check_sp_msg(&resp_msg, ARM_SVC_ID_SP_EVENT_COMPLETE, MM_RETURN_CODE_INVALID_PARAMETER,
- 0, 0, 0);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_INVALID_PARAMETER, 0, 0, 0, 0);
}
-TEST(mm_communicate_call_ep, mm_communicate_length_overflow)
+TEST(mm_communicate_call_ep, mm_communicate_offset_overflow)
{
CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
+ req_msg.args.args64[0] = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE + 1;
+
+ mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- req_msg.args[0] = (uintptr_t)comm_buffer;
- req_msg.args[1] = sizeof(comm_buffer);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_INVALID_PARAMETER, 0, 0, 0, 0);
+}
+TEST(mm_communicate_call_ep, mm_communicate_length_overflow)
+{
+ CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
header->MessageLength = UINT64_MAX - EFI_MM_COMMUNICATE_HEADER_SIZE + 1;
mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- check_sp_msg(&resp_msg, ARM_SVC_ID_SP_EVENT_COMPLETE, MM_RETURN_CODE_INVALID_PARAMETER,
- 0, 0, 0);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_INVALID_PARAMETER, 0, 0, 0, 0);
}
TEST(mm_communicate_call_ep, mm_communicate_too_large)
{
CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
-
- req_msg.args[0] = (uintptr_t)comm_buffer;
- req_msg.args[1] = sizeof(comm_buffer);
-
header->MessageLength = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE + 1;
mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- check_sp_msg(&resp_msg, ARM_SVC_ID_SP_EVENT_COMPLETE, MM_RETURN_CODE_INVALID_PARAMETER,
- 0, 0, 0);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_INVALID_PARAMETER, 0, 0, 0, 0);
}
TEST(mm_communicate_call_ep, mm_communicate_no_handler)
{
CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
-
- req_msg.args[0] = (uintptr_t)comm_buffer;
- req_msg.args[1] = sizeof(comm_buffer);
-
header->MessageLength = 0;
mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- check_sp_msg(&resp_msg, ARM_SVC_ID_SP_EVENT_COMPLETE, MM_RETURN_CODE_NOT_SUPPORTED,
- 0, 0, 0);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_NOT_SUPPORTED, 0, 0, 0, 0);
}
TEST(mm_communicate_call_ep, mm_communicate_single_handler_not_matching)
@@ -175,16 +170,11 @@ TEST(mm_communicate_call_ep, mm_communicate_single_handler_not_matching)
CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
mm_communicate_call_ep_attach_service(&call_ep, &guid0, &iface);
-
- req_msg.args[0] = (uintptr_t)comm_buffer;
- req_msg.args[1] = sizeof(comm_buffer);
-
header->MessageLength = 0;
mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- check_sp_msg(&resp_msg, ARM_SVC_ID_SP_EVENT_COMPLETE, MM_RETURN_CODE_NOT_SUPPORTED,
- 0, 0, 0);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_NOT_SUPPORTED, 0, 0, 0, 0);
}
TEST(mm_communicate_call_ep, mm_communicate_single_handler_matching)
@@ -197,33 +187,69 @@ TEST(mm_communicate_call_ep, mm_communicate_single_handler_matching)
struct mm_service_call_req req = {
.guid = &guid0,
.req_buf = {
- .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE,
- .data_len = req_len,
- .data = header->Data
+ .data = header->Data,
+ .data_length = req_len,
+ .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE
},
.resp_buf = {
- .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE,
- .data_len = 0,
- .data = header->Data
+ .data = header->Data,
+ .data_length = 0,
+ .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE
},
};
CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
mm_communicate_call_ep_attach_service(&call_ep, &guid0, &iface);
- req_msg.args[0] = (uintptr_t)comm_buffer;
- req_msg.args[1] = sizeof(comm_buffer);
+ memcpy(&header->HeaderGuid, &guid0, sizeof(guid0));
+ header->MessageLength = req_len;
+
+ expect_mock_mm_service_receive(&iface, &req, MM_RETURN_CODE_SUCCESS);
+
+ mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
+
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_SUCCESS, 0, 0, 0, 0);
+}
+
+TEST(mm_communicate_call_ep, mm_communicate_single_handler_matching_with_offset)
+{
+ const size_t offset = 0x10;
+ EFI_MM_COMMUNICATE_HEADER *header = (EFI_MM_COMMUNICATE_HEADER *)(comm_buffer + offset);
+
+ const size_t req_len = 16;
+ struct mm_service_interface iface = {
+ .context = (void *)0x1234,
+ .receive = mock_mm_service_receive
+ };
+ struct mm_service_call_req req = {
+ .guid = &guid0,
+ .req_buf = {
+ .data = header->Data,
+ .data_length = req_len,
+ .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE - offset
+ },
+ .resp_buf = {
+ .data = header->Data,
+ .data_length = 0,
+ .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE - offset
+ },
+ };
+
+ CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
+ mm_communicate_call_ep_attach_service(&call_ep, &guid0, &iface);
memcpy(&header->HeaderGuid, &guid0, sizeof(guid0));
header->MessageLength = req_len;
+ req_msg.args.args64[0] = offset;
expect_mock_mm_service_receive(&iface, &req, MM_RETURN_CODE_SUCCESS);
mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- check_sp_msg(&resp_msg, ARM_SVC_ID_SP_EVENT_COMPLETE, MM_RETURN_CODE_SUCCESS, 0, 0, 0);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_SUCCESS, 0, 0, 0, 0);
}
+
TEST(mm_communicate_call_ep, mm_communicate_single_handler_matching_error)
{
const size_t req_len = 16;
@@ -234,23 +260,20 @@ TEST(mm_communicate_call_ep, mm_communicate_single_handler_matching_error)
struct mm_service_call_req req = {
.guid = &guid0,
.req_buf = {
- .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE,
- .data_len = req_len,
- .data = header->Data
+ .data = header->Data,
+ .data_length = req_len,
+ .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE
},
.resp_buf = {
- .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE,
- .data_len = 0,
- .data = header->Data
+ .data = header->Data,
+ .data_length = 0,
+ .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE
},
};
CHECK_TRUE(mm_communicate_call_ep_init(&call_ep, comm_buffer, sizeof(comm_buffer)));
mm_communicate_call_ep_attach_service(&call_ep, &guid0, &iface);
- req_msg.args[0] = (uintptr_t)comm_buffer;
- req_msg.args[1] = sizeof(comm_buffer);
-
memcpy(&header->HeaderGuid, &guid0, sizeof(guid0));
header->MessageLength = req_len;
@@ -258,7 +281,7 @@ TEST(mm_communicate_call_ep, mm_communicate_single_handler_matching_error)
mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- check_sp_msg(&resp_msg, ARM_SVC_ID_SP_EVENT_COMPLETE, MM_RETURN_CODE_NO_MEMORY, 0, 0, 0);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_NO_MEMORY, 0, 0, 0, 0);
}
TEST(mm_communicate_call_ep, mm_communicate_two_handlers)
@@ -275,14 +298,14 @@ TEST(mm_communicate_call_ep, mm_communicate_two_handlers)
struct mm_service_call_req req = {
.guid = &guid1,
.req_buf = {
- .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE,
- .data_len = req_len,
- .data = header->Data
+ .data = header->Data,
+ .data_length = req_len,
+ .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE
},
.resp_buf = {
- .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE,
- .data_len = 0,
- .data = header->Data
+ .data = header->Data,
+ .data_length = 0,
+ .size = sizeof(comm_buffer) - EFI_MM_COMMUNICATE_HEADER_SIZE
},
};
@@ -290,9 +313,6 @@ TEST(mm_communicate_call_ep, mm_communicate_two_handlers)
mm_communicate_call_ep_attach_service(&call_ep, &guid0, &iface0);
mm_communicate_call_ep_attach_service(&call_ep, &guid1, &iface1);
- req_msg.args[0] = (uintptr_t)comm_buffer;
- req_msg.args[1] = sizeof(comm_buffer);
-
memcpy(&header->HeaderGuid, &guid1, sizeof(guid0));
header->MessageLength = req_len;
@@ -300,5 +320,5 @@ TEST(mm_communicate_call_ep, mm_communicate_two_handlers)
mm_communicate_call_ep_receive(&call_ep, &req_msg, &resp_msg);
- check_sp_msg(&resp_msg, ARM_SVC_ID_SP_EVENT_COMPLETE, MM_RETURN_CODE_SUCCESS, 0, 0, 0);
+ check_sp_msg(&resp_msg, MM_RETURN_CODE_SUCCESS, 0, 0, 0, 0);
}
diff --git a/components/rpc/mm_communicate/endpoint/sp/test/test_mock_mm_service.cpp b/components/rpc/mm_communicate/endpoint/sp/test/test_mock_mm_service.cpp
index 360a8fa66..5e9149fd8 100644
--- a/components/rpc/mm_communicate/endpoint/sp/test/test_mock_mm_service.cpp
+++ b/components/rpc/mm_communicate/endpoint/sp/test/test_mock_mm_service.cpp
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#include <CppUTest/TestHarness.h>
@@ -34,17 +34,17 @@ TEST(mock_mm_service, receive)
struct mm_service_call_req req = {
&guid,
.req_buf = {
- .size = 20,
- .data_len = 12,
- .data = (void *)0x1234
+ .data = (uint8_t *)0x1234,
+ .data_length = 12,
+ .size = 20
},
.resp_buf = {
- .size = 30,
- .data_len = 15,
- .data = (void *)0x2345
+ .data = (uint8_t *)0x2345,
+ .data_length = 15,
+ .size = 30
}
};
- int32_t result = -123456;
+ int64_t result = -123456;
expect_mock_mm_service_receive(&iface, &req, result);
LONGS_EQUAL(result, mock_mm_service_receive(&iface, &req));
diff --git a/components/rpc/mm_communicate/endpoint/sp/tests.cmake b/components/rpc/mm_communicate/endpoint/sp/tests.cmake
index 318f14d70..c68a0c7eb 100644
--- a/components/rpc/mm_communicate/endpoint/sp/tests.cmake
+++ b/components/rpc/mm_communicate/endpoint/sp/tests.cmake
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2021, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -13,12 +13,12 @@ unit_test_add_suite(
${CMAKE_CURRENT_LIST_DIR}/test/test_mm_communicate_call_ep.cpp
${CMAKE_CURRENT_LIST_DIR}/test/mock_mm_service.cpp
${CMAKE_CURRENT_LIST_DIR}/test/test_mock_mm_service.cpp
- ${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/test/mock_assert.cpp
+ ${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/mock/mock_assert.cpp
INCLUDE_DIRECTORIES
${UNIT_TEST_PROJECT_PATH}
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/include
- ${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/test
+ ${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/mock
${UNIT_TEST_PROJECT_PATH}/components/rpc/common/interface
COMPILE_DEFINITIONS
-DARM64
diff --git a/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.c b/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.c
new file mode 100644
index 000000000..499915a86
--- /dev/null
+++ b/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "psa_ipc_caller.h"
+#include "rpc_caller.h"
+#include "rpc_status.h"
+#include <openamp_messenger_api.h>
+#include <trace.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+struct psa_ipc_caller_context {
+ struct openamp_messenger openamp;
+};
+
+rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid, uint16_t endpoint_id)
+{
+ return RPC_SUCCESS;
+}
+
+rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid)
+{
+ return RPC_SUCCESS;
+}
+
+rpc_status_t close_session(void *context)
+{
+ return RPC_SUCCESS;
+}
+
+rpc_status_t create_shared_memory(void *context, size_t size,
+ struct rpc_caller_shared_memory *shared_memory)
+{
+ return RPC_ERROR_INVALID_VALUE;
+}
+
+rpc_status_t release_shared_memory(void *context, struct rpc_caller_shared_memory *shared_memory)
+{
+ return RPC_ERROR_INVALID_VALUE;
+}
+
+rpc_status_t call(void *context, uint16_t opcode, struct rpc_caller_shared_memory *shared_memory,
+ size_t request_length, size_t *response_length, service_status_t *service_status)
+{
+ return RPC_ERROR_INTERNAL;
+}
+
+void *psa_ipc_phys_to_virt(void *context, void *pa)
+{
+ struct psa_ipc_caller_context *caller = (struct psa_ipc_caller_context *)context;
+ struct openamp_messenger *openamp = &caller->openamp;
+
+ return openamp_messenger_phys_to_virt(openamp, pa);
+}
+
+void *psa_ipc_virt_to_phys(void *context, void *va)
+{
+ struct psa_ipc_caller_context *caller = (struct psa_ipc_caller_context *)context;
+ struct openamp_messenger *openamp = &caller->openamp;
+
+ return openamp_messenger_virt_to_phys(openamp, va);
+}
+
+rpc_status_t psa_ipc_caller_init(struct rpc_caller_interface *rpc_caller)
+{
+ struct psa_ipc_caller_context *context = NULL;
+ int ret = 0;
+
+ if (!rpc_caller || rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ context = (struct psa_ipc_caller_context *)calloc(1, sizeof(struct psa_ipc_caller_context));
+ if (!context)
+ return RPC_ERROR_INTERNAL;
+
+ ret = openamp_messenger_init(&context->openamp);
+ if (ret < 0) {
+ free(context);
+ return RPC_ERROR_TRANSPORT_LAYER;
+ }
+
+ rpc_caller->context = context;
+ rpc_caller->open_session = open_session;
+ rpc_caller->find_and_open_session = find_and_open_session;
+ rpc_caller->close_session = close_session;
+ rpc_caller->create_shared_memory = create_shared_memory;
+ rpc_caller->release_shared_memory = release_shared_memory;
+ rpc_caller->call = call;
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t psa_ipc_caller_deinit(struct rpc_caller_interface *rpc_caller)
+{
+ struct psa_ipc_caller_context *context = NULL;
+
+ context = (struct psa_ipc_caller_context *)rpc_caller->context;
+
+ openamp_messenger_deinit(&context->openamp);
+
+ free(context);
+
+ return RPC_SUCCESS;
+}
+
+psa_ipc_call_handle psa_ipc_caller_begin(struct rpc_caller_interface *caller,
+ uint8_t **request_buffer,
+ size_t request_length)
+{
+ struct psa_ipc_caller_context *context = NULL;
+ int ret = 0;
+
+ if (!caller || !caller->context)
+ return NULL;
+
+ context = (struct psa_ipc_caller_context *)caller->context;
+
+ ret = openamp_messenger_call_begin(&context->openamp, request_buffer, request_length);
+ if (ret < 0)
+ return NULL;
+
+ return caller;
+
+}
+
+rpc_status_t psa_ipc_caller_invoke(psa_ipc_call_handle handle, uint32_t opcode,
+ uint8_t **response_buffer, size_t *response_length)
+{
+ struct rpc_caller_interface *caller = (struct rpc_caller_interface *)handle;
+ struct psa_ipc_caller_context *context = NULL;
+ int ret = 0;
+
+ if (!handle || !caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ context = (struct psa_ipc_caller_context *)caller->context;
+
+ ret = openamp_messenger_call_invoke(&context->openamp, response_buffer, response_length);
+ if (ret < 0)
+ return RPC_ERROR_TRANSPORT_LAYER;
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t psa_ipc_caller_end(psa_ipc_call_handle handle)
+{
+ struct rpc_caller_interface *caller = (struct rpc_caller_interface *)handle;
+ struct psa_ipc_caller_context *context = NULL;
+
+ if (!handle || !caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ context = (struct psa_ipc_caller_context *)caller->context;
+
+ openamp_messenger_call_end(&context->openamp);
+
+ return RPC_SUCCESS;
+} \ No newline at end of file
diff --git a/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.h b/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.h
new file mode 100644
index 000000000..f415ccc3a
--- /dev/null
+++ b/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpc_caller_session.h"
+#include <openamp_messenger_api.h>
+
+typedef void *psa_ipc_call_handle;
+
+void *psa_ipc_phys_to_virt(void *context, void *pa);
+void *psa_ipc_virt_to_phys(void *context, void *va);
+
+rpc_status_t psa_ipc_caller_init(struct rpc_caller_interface *rpc_caller);
+rpc_status_t psa_ipc_caller_deinit(struct rpc_caller_interface *rpc_caller);
+
+psa_ipc_call_handle psa_ipc_caller_begin(struct rpc_caller_interface *caller,
+ uint8_t **request_buffer,
+ size_t request_length);
+
+rpc_status_t psa_ipc_caller_invoke(psa_ipc_call_handle handle, uint32_t opcode,
+ uint8_t **response_buffer,
+ size_t *response_length);
+
+rpc_status_t psa_ipc_caller_end(psa_ipc_call_handle handle); \ No newline at end of file
diff --git a/components/rpc/psa_ipc/component.cmake b/components/rpc/psa_ipc/component.cmake
new file mode 100644
index 000000000..5d9c72be2
--- /dev/null
+++ b/components/rpc/psa_ipc/component.cmake
@@ -0,0 +1,24 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+ ${CMAKE_CURRENT_LIST_DIR}/caller/sp/psa_ipc_caller.h
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/service_psa_ipc.c"
+ "${CMAKE_CURRENT_LIST_DIR}/caller/sp/psa_ipc_caller.c"
+ )
+
+target_include_directories(${TGT}
+ PUBLIC
+ "${CMAKE_CURRENT_LIST_DIR}/caller/sp/"
+ )
+
diff --git a/components/rpc/psa_ipc/service_psa_ipc.c b/components/rpc/psa_ipc/service_psa_ipc.c
new file mode 100644
index 000000000..36c8e3679
--- /dev/null
+++ b/components/rpc/psa_ipc/service_psa_ipc.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <trace.h>
+
+#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/error.h>
+#include <rpc_caller.h>
+
+#include <psa/client.h>
+#include <psa_ipc_caller.h>
+#include "service_psa_ipc_openamp_lib.h"
+
+static inline void *unaligned_memcpy(void *dst_init, const void *src_init,
+ size_t len)
+{
+ char *dst = dst_init;
+ const char *src = src_init;
+
+ while (len--)
+ *dst++ = *src++;
+
+ return dst_init;
+}
+
+static struct psa_invec *psa_call_in_vec_param(uint8_t *req)
+{
+ return (struct psa_invec *)(req + sizeof(struct ns_openamp_msg));
+}
+
+static struct psa_outvec *psa_call_out_vec_param(uint8_t *req, size_t in_len)
+{
+ return (struct psa_outvec *)(req + sizeof(struct ns_openamp_msg) +
+ (in_len * sizeof(struct psa_invec)));
+}
+
+static size_t psa_call_header_len(const struct psa_invec *in_vec, size_t in_len,
+ struct psa_outvec *out_vec, size_t out_len)
+{
+ return sizeof(struct ns_openamp_msg) + (in_len * sizeof(*in_vec)) +
+ (out_len * sizeof(*out_vec));
+}
+
+static size_t psa_call_in_vec_len(const struct psa_invec *in_vec, size_t in_len)
+{
+ size_t req_len = 0;
+ int i = 0;
+
+ if (!in_vec || !in_len)
+ return 0;
+
+ for (i = 0; i < in_len; i++)
+ req_len += in_vec[i].len;
+
+ return req_len;
+}
+
+static uint32_t psa_virt_to_phys_u32(struct rpc_caller_interface *caller, void *va)
+{
+ return (uintptr_t)psa_ipc_virt_to_phys(caller->context, va);
+}
+
+psa_handle_t psa_connect(struct rpc_caller_interface *caller, uint32_t sid,
+ uint32_t version)
+{
+ struct s_openamp_msg *resp_msg;
+ struct ns_openamp_msg *req_msg;
+ psa_ipc_call_handle rpc_handle;
+ size_t resp_len;
+ uint8_t *resp;
+ uint8_t *req;
+ int ret;
+
+ rpc_handle = psa_ipc_caller_begin(caller, &req, sizeof(struct ns_openamp_msg));
+ if (!rpc_handle) {
+ EMSG("psa_connect: could not get rpc handle");
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ req_msg = (struct ns_openamp_msg *)req;
+
+ req_msg->call_type = OPENAMP_PSA_CONNECT;
+ req_msg->params.psa_connect_params.sid = sid;
+ req_msg->params.psa_connect_params.version = version;
+
+ ret = psa_ipc_caller_invoke(rpc_handle, 0, &resp, &resp_len);
+ if (ret != RPC_SUCCESS) {
+ EMSG("invoke failed: %d", ret);
+ return PSA_NULL_HANDLE;
+ }
+
+ resp_msg = (struct s_openamp_msg *)resp;
+
+ psa_ipc_caller_end(rpc_handle);
+
+ return resp_msg ? (psa_handle_t)resp_msg->reply : PSA_NULL_HANDLE;
+}
+
+static psa_status_t __psa_call(struct rpc_caller_interface *caller, psa_handle_t psa_handle,
+ int32_t client_id, int32_t type,
+ const struct psa_invec *in_vec, size_t in_len,
+ struct psa_outvec *out_vec, size_t out_len)
+{
+ struct s_openamp_msg *resp_msg = NULL;
+ struct psa_outvec *out_vec_param;
+ struct psa_invec *in_vec_param;
+ struct ns_openamp_msg *req_msg;
+ psa_ipc_call_handle rpc_handle;
+ size_t in_vec_len;
+ size_t header_len;
+ uint8_t *payload;
+ size_t resp_len;
+ uint8_t *resp;
+ uint8_t *req;
+ int ret;
+ int i;
+
+ if ((psa_handle == PSA_NULL_HANDLE) || !caller)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ header_len = psa_call_header_len(in_vec, in_len, out_vec, out_len);
+ in_vec_len = psa_call_in_vec_len(in_vec, in_len);
+
+ rpc_handle = psa_ipc_caller_begin(caller, &req, header_len + in_vec_len);
+ if (!rpc_handle) {
+ EMSG("psa_call: could not get handle");
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ payload = req + header_len;
+
+ out_vec_param = psa_call_out_vec_param(req, in_len);
+ in_vec_param = psa_call_in_vec_param(req);
+
+ req_msg = (struct ns_openamp_msg *)req;
+
+ req_msg->call_type = OPENAMP_PSA_CALL;
+ req_msg->request_id = 1234;
+ req_msg->client_id = client_id;
+ req_msg->params.psa_call_params.handle = psa_handle;
+ req_msg->params.psa_call_params.type = type;
+ req_msg->params.psa_call_params.in_len = in_len;
+ req_msg->params.psa_call_params.in_vec = psa_virt_to_phys_u32(caller, in_vec_param);
+ req_msg->params.psa_call_params.out_len = out_len;
+ req_msg->params.psa_call_params.out_vec = psa_virt_to_phys_u32(caller, out_vec_param);
+
+ for (i = 0; i < in_len; i++) {
+ in_vec_param[i].base = psa_virt_to_phys_u32(caller, payload);
+ in_vec_param[i].len = in_vec[i].len;
+
+ unaligned_memcpy(payload, psa_u32_to_ptr(in_vec[i].base),
+ in_vec[i].len);
+ payload += in_vec[i].len;
+ }
+
+ for (i = 0; i < out_len; i++) {
+ out_vec_param[i].base = 0;
+ out_vec_param[i].len = out_vec[i].len;
+ }
+
+ ret = psa_ipc_caller_invoke(rpc_handle, 0, &resp, &resp_len);
+ if (ret != RPC_SUCCESS) {
+ EMSG("psa_call: invoke failed: %d", ret);
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ resp_msg = (struct s_openamp_msg *)resp;
+
+ if (!resp_msg || !out_len || resp_msg->reply != PSA_SUCCESS)
+ goto caller_end;
+
+ out_vec_param = (struct psa_outvec *)psa_ipc_phys_to_virt(caller,
+ psa_u32_to_ptr(resp_msg->params.out_vec));
+
+ for (i = 0; i < resp_msg->params.out_len; i++) {
+ out_vec[i].len = out_vec_param[i].len;
+ unaligned_memcpy(psa_u32_to_ptr(out_vec[i].base),
+ psa_ipc_phys_to_virt(caller,
+ psa_u32_to_ptr(out_vec_param[i].base)),
+ out_vec[i].len);
+ }
+
+caller_end:
+ psa_ipc_caller_end(rpc_handle);
+
+ return resp_msg ? resp_msg->reply : PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_call_client_id(struct rpc_caller_interface *caller,
+ psa_handle_t psa_handle, int32_t client_id,
+ int32_t type, const struct psa_invec *in_vec,
+ size_t in_len, struct psa_outvec *out_vec,
+ size_t out_len)
+{
+ return __psa_call(caller, psa_handle, client_id, type, in_vec, in_len,
+ out_vec, out_len);
+}
+
+psa_status_t psa_call(struct rpc_caller_interface *caller, psa_handle_t psa_handle,
+ int32_t type, const struct psa_invec *in_vec,
+ size_t in_len, struct psa_outvec *out_vec, size_t out_len)
+{
+ return __psa_call(caller, psa_handle, 0, type, in_vec, in_len, out_vec,
+ out_len);
+}
+
+void psa_close(struct rpc_caller_interface *caller, psa_handle_t psa_handle)
+{
+ struct ns_openamp_msg *req_msg;
+ psa_ipc_call_handle rpc_handle;
+ size_t resp_len;
+ uint8_t *resp;
+ uint8_t *req;
+ int ret;
+
+ if ((psa_handle == PSA_NULL_HANDLE) || !caller)
+ return;
+
+ rpc_handle = psa_ipc_caller_begin(caller, &req, sizeof(struct ns_openamp_msg));
+ if (!rpc_handle) {
+ EMSG("psa_close: could not get handle");
+ return;
+ }
+
+ req_msg = (struct ns_openamp_msg *)req;
+
+ req_msg->call_type = OPENAMP_PSA_CLOSE;
+ req_msg->params.psa_close_params.handle = psa_handle;
+
+ ret = psa_ipc_caller_invoke(rpc_handle, 0, &resp, &resp_len);
+ if (ret != TS_RPC_CALL_ACCEPTED) {
+ EMSG("psa_close: invoke failed: %d", ret);
+ return;
+ }
+
+ psa_ipc_caller_end(rpc_handle);
+}
diff --git a/components/rpc/psa_ipc/service_psa_ipc_openamp_lib.h b/components/rpc/psa_ipc/service_psa_ipc_openamp_lib.h
new file mode 100644
index 000000000..38ad2edd8
--- /dev/null
+++ b/components/rpc/psa_ipc/service_psa_ipc_openamp_lib.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SERVICE_PSA_IPC_OPENAMP_LIB_H
+#define SERVICE_PSA_IPC_OPENAMP_LIB_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <compiler.h>
+#include <psa/error.h>
+
+#include <stdint.h>
+#include <psa/client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* PSA client call type value */
+#define OPENAMP_PSA_FRAMEWORK_VERSION (0x1)
+#define OPENAMP_PSA_VERSION (0x2)
+#define OPENAMP_PSA_CONNECT (0x3)
+#define OPENAMP_PSA_CALL (0x4)
+#define OPENAMP_PSA_CLOSE (0x5)
+
+/* Return code of openamp APIs */
+#define OPENAMP_SUCCESS (0)
+#define OPENAMP_MAP_FULL (INT32_MIN + 1)
+#define OPENAMP_MAP_ERROR (INT32_MIN + 2)
+#define OPENAMP_INVAL_PARAMS (INT32_MIN + 3)
+#define OPENAMP_NO_PERMS (INT32_MIN + 4)
+#define OPENAMP_NO_PEND_EVENT (INT32_MIN + 5)
+#define OPENAMP_CHAN_BUSY (INT32_MIN + 6)
+#define OPENAMP_CALLBACK_REG_ERROR (INT32_MIN + 7)
+#define OPENAMP_INIT_ERROR (INT32_MIN + 8)
+
+#define HOLD_INPUT_BUFFER (1) /* IF true, TF-M Library will hold the openamp
+ * buffer so that openamp shared memory buffer
+ * does not get freed.
+ */
+
+/*
+ * This structure holds the parameters used in a PSA client call.
+ */
+typedef struct __packed psa_client_in_params {
+ union {
+ struct __packed {
+ uint32_t sid;
+ } psa_version_params;
+
+ struct __packed {
+ uint32_t sid;
+ uint32_t version;
+ } psa_connect_params;
+
+ struct __packed {
+ psa_handle_t handle;
+ int32_t type;
+ uint32_t in_vec;
+ uint32_t in_len;
+ uint32_t out_vec;
+ uint32_t out_len;
+ } psa_call_params;
+
+ struct __packed {
+ psa_handle_t handle;
+ } psa_close_params;
+ };
+} psa_client_in_params_t;
+
+/* Openamp message passed from NSPE to SPE to deliver a PSA client call */
+struct __packed ns_openamp_msg {
+ uint32_t call_type; /* PSA client call type */
+ struct psa_client_in_params params; /* Contain parameters used in PSA
+ * client call
+ */
+
+ int32_t client_id; /* Optional client ID of the
+ * non-secure caller.
+ * It is required to identify the
+ * non-secure task when NSPE OS
+ * enforces non-secure task
+ * isolation
+ */
+ int32_t request_id; /* This is the unique ID for a
+ * request send to TF-M by the
+ * non-secure core. TF-M forward
+ * the ID back to non-secure on the
+ * reply to a given request. Using
+ * this id, the non-secure library
+ * can identify the request for
+ * which the reply has received.
+ */
+};
+
+/*
+ * This structure holds the location of the out data of the PSA client call.
+ */
+struct __packed psa_client_out_params {
+ uint32_t out_vec;
+ uint32_t out_len;
+};
+
+
+/* Openamp message from SPE to NSPE delivering the reply back for a PSA client
+ * call.
+ */
+struct __packed s_openamp_msg {
+ int32_t request_id; /* Using this id, the non-secure
+ * library identifies the request.
+ * TF-M forwards the same
+ * request-id received on the
+ * initial request.
+ */
+ int32_t reply; /* Reply of the PSA client call */
+ struct psa_client_out_params params; /* Contain out data result of the
+ * PSA client call.
+ */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERVICE_PSA_IPC_OPENAMP_LIB_H */
+
+
diff --git a/components/rpc/ts_rpc/caller/linux/component.cmake b/components/rpc/ts_rpc/caller/linux/component.cmake
new file mode 100644
index 000000000..c9f439e20
--- /dev/null
+++ b/components/rpc/ts_rpc/caller/linux/component.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+include(${TS_ROOT}/external/LinuxFfaTeeDriver/LinuxFfaTeeDriver.cmake)
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+ "${CMAKE_CURRENT_LIST_DIR}/ts_rpc_caller_linux.h"
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ts_rpc_caller_linux.c"
+ )
+
+target_include_directories(${TGT} PRIVATE
+ "${LINUX_FFA_TEE_DRIVER_INCLUDE_DIR}"
+ )
diff --git a/components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.c b/components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.c
new file mode 100644
index 000000000..7c4606e56
--- /dev/null
+++ b/components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "ts_rpc_caller_linux.h"
+
+#include <arm_tstee.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/tee.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <util.h>
+
+#define INVALID_SESS_ID 0
+#define MAX_TEE_DEV_NUM 16
+#define TS_TEE_DRV_REQ_VER_MAJOR 2
+#define TS_TEE_DRV_REQ_VER_MINOR 0
+#define TS_TEE_DRV_REQ_VER_PATCH 0
+#define TS_TEE_DRV_INVALID_SHM_ID (0)
+
+struct ts_tee_dev {
+ uint16_t endpoint_id;
+ char path[16];
+};
+
+struct ts_rpc_caller_linux_context {
+ struct ts_tee_dev ts_tee_devs[MAX_TEE_DEV_NUM];
+ uint32_t session_id;
+ int fd;
+};
+
+#define TEE_IOC_OPEN_SESSION_NUM_PARAMS 0
+static rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid,
+ uint16_t endpoint_id)
+{
+ struct ts_rpc_caller_linux_context *caller = (struct ts_rpc_caller_linux_context *)context;
+ const size_t arg_size = sizeof(struct tee_ioctl_open_session_arg) +
+ TEE_IOC_OPEN_SESSION_NUM_PARAMS * sizeof(struct tee_ioctl_param);
+ union {
+ struct tee_ioctl_open_session_arg arg;
+ uint8_t data[arg_size];
+ } buf;
+ struct tee_ioctl_open_session_arg *arg = NULL;
+ struct tee_ioctl_buf_data buf_data = { 0 };
+ struct ts_tee_dev *dev = NULL;
+ int rc = -1;
+
+ if (caller->fd >= 0 || caller->session_id != INVALID_SESS_ID) {
+ printf("%s():%d session is already opened\n", __func__, __LINE__);
+ return RPC_ERROR_INVALID_STATE;
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(caller->ts_tee_devs); i++) {
+ if (caller->ts_tee_devs[i].endpoint_id == endpoint_id) {
+ dev = &caller->ts_tee_devs[i];
+ break;
+ }
+ }
+
+ if (!dev) {
+ printf("%s():%d cannot find device for 0x%04x\n", __func__, __LINE__, endpoint_id);
+ return RPC_ERROR_NOT_FOUND;
+ }
+
+ caller->fd = open(dev->path, O_RDWR);
+ if (caller->fd < 0) {
+ printf("%s():%d cannot open %s: %d\n", __func__, __LINE__, dev->path, errno);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ memset(&buf, 0, sizeof(buf));
+
+ buf_data.buf_ptr = (uintptr_t)&buf;
+ buf_data.buf_len = sizeof(buf);
+
+ arg = &buf.arg;
+ arg->num_params = TEE_IOC_OPEN_SESSION_NUM_PARAMS;
+
+ memcpy(arg->uuid, service_uuid->uuid, sizeof(service_uuid->uuid));
+
+ rc = ioctl(caller->fd, TEE_IOC_OPEN_SESSION, &buf_data);
+ if (rc) {
+ close(caller->fd);
+ caller->fd = -1;
+ return RPC_ERROR_INTERNAL;
+ }
+
+ caller->session_id = arg->session;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid)
+{
+ struct ts_rpc_caller_linux_context *caller = (struct ts_rpc_caller_linux_context *)context;
+
+ for (int i = 0; i < ARRAY_SIZE(caller->ts_tee_devs); i++) {
+ if (!open_session(context, service_uuid, caller->ts_tee_devs[i].endpoint_id))
+ return RPC_SUCCESS;
+ }
+
+ return RPC_ERROR_INTERNAL;
+}
+
+rpc_status_t close_session(void *context)
+{
+ struct ts_rpc_caller_linux_context *caller = (struct ts_rpc_caller_linux_context *)context;
+ struct tee_ioctl_close_session_arg arg = { 0 };
+ int rc = -1;
+
+ if (caller->fd < 0) {
+ printf("%s():%d session is already closed\n", __func__, __LINE__);
+ return RPC_ERROR_INVALID_STATE;
+ }
+
+ arg.session = caller->session_id;
+
+ rc = ioctl(caller->fd, TEE_IOC_CLOSE_SESSION, &arg);
+ if (rc) {
+ printf("%s():%d failed to close session: %d\n", __func__, __LINE__, errno);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ close(caller->fd);
+ caller->fd = -1;
+ caller->session_id = INVALID_SESS_ID;
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t create_shared_memory(void *context, size_t size,
+ struct rpc_caller_shared_memory *shared_memory)
+{
+ struct ts_rpc_caller_linux_context *caller = (struct ts_rpc_caller_linux_context *)context;
+ struct tee_ioctl_shm_alloc_data data = { .size = size };
+ int shm_fd = -1;
+
+ if (!size) {
+ shared_memory->buffer = NULL;
+ shared_memory->size = 0;
+ shared_memory->id = TS_TEE_DRV_INVALID_SHM_ID;
+
+ return RPC_SUCCESS;
+ }
+
+ shm_fd = ioctl(caller->fd, TEE_IOC_SHM_ALLOC, &data);
+ if (shm_fd < 0) {
+ printf("%s():%d failed to create shared memory: %d\n", __func__, __LINE__, errno);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ shared_memory->buffer =
+ mmap(NULL, data.size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+ if (shared_memory->buffer == (void *)MAP_FAILED) {
+ printf("%s():%d failed to map shared memory: %d\n", __func__, __LINE__, errno);
+ close(shm_fd);
+ return RPC_ERROR_INTERNAL;
+ }
+ close(shm_fd);
+ shared_memory->size = data.size;
+ shared_memory->id = data.id;
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t release_shared_memory(void *context, struct rpc_caller_shared_memory *shared_memory)
+{
+ (void)context;
+
+ if (shared_memory->id == TS_TEE_DRV_INVALID_SHM_ID)
+ return RPC_SUCCESS;
+
+ if (munmap(shared_memory->buffer, shared_memory->size)) {
+ printf("%s():%d failed to unmap shared memory: %d\n", __func__, __LINE__, errno);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ *shared_memory = (struct rpc_caller_shared_memory){ 0 };
+
+ return RPC_SUCCESS;
+}
+
+#define TEE_IOC_INVOKE_NUM_PARAMS 1
+static rpc_status_t call(void *context, uint16_t opcode,
+ struct rpc_caller_shared_memory *shared_memory, size_t request_length,
+ size_t *response_length, service_status_t *service_status)
+{
+ struct ts_rpc_caller_linux_context *caller = (struct ts_rpc_caller_linux_context *)context;
+ const size_t arg_size = sizeof(struct tee_ioctl_invoke_arg) +
+ TEE_IOC_INVOKE_NUM_PARAMS * sizeof(struct tee_ioctl_param);
+ union {
+ struct tee_ioctl_invoke_arg arg;
+ uint8_t data[arg_size];
+ } buf;
+ struct tee_ioctl_buf_data buf_data = { 0 };
+ struct tee_ioctl_invoke_arg *arg = NULL;
+ struct tee_ioctl_param *params = NULL;
+ int rc = -1;
+
+ memset(&buf, 0, sizeof(buf));
+
+ buf_data.buf_ptr = (uintptr_t)&buf;
+ buf_data.buf_len = sizeof(buf);
+
+ arg = &buf.arg;
+ arg->func = opcode;
+ arg->session = caller->session_id;
+ arg->num_params = TEE_IOC_INVOKE_NUM_PARAMS;
+ params = (struct tee_ioctl_param *)(arg + 1);
+
+ params[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
+ params[0].a = shared_memory->id;
+ params[0].b = request_length;
+ params[0].c = 0;
+
+ rc = ioctl(caller->fd, TEE_IOC_INVOKE, &buf_data);
+ if (rc) {
+ printf("%s():%d failed to invoke command: %d\n", __func__, __LINE__, errno);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ *response_length = params[0].a;
+ *service_status = (int)arg->ret;
+
+ return RPC_SUCCESS;
+}
+
+static bool ts_tee_drv_check_version(void)
+{
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ unsigned int patch = 0;
+ FILE *f = NULL;
+ int cnt = 0;
+
+ f = fopen("/sys/module/arm_tstee/version", "r");
+ if (f) {
+ cnt = fscanf(f, "%u.%u.%u", &major, &minor, &patch);
+ fclose(f);
+
+ if (cnt != 3) {
+ printf("error: cannot read TS TEE driver version\n");
+ return false;
+ }
+ } else {
+ printf("error: TS TEE driver not available\n");
+ return false;
+ }
+
+ if (major != TS_TEE_DRV_REQ_VER_MAJOR)
+ goto err;
+
+ if (minor < TS_TEE_DRV_REQ_VER_MINOR)
+ goto err;
+
+ if (minor == TS_TEE_DRV_REQ_VER_MINOR)
+ if (patch < TS_TEE_DRV_REQ_VER_PATCH)
+ goto err;
+
+ return true;
+
+err:
+ printf("error: TS TEE driver is v%u.%u.%u but required v%u.%u.%u\n", major, minor, patch,
+ TS_TEE_DRV_REQ_VER_MAJOR, TS_TEE_DRV_REQ_VER_MINOR, TS_TEE_DRV_REQ_VER_PATCH);
+
+ return false;
+}
+
+static void ts_tee_drv_discover(struct ts_tee_dev *ts_tee_devs, size_t count)
+{
+ struct tee_ioctl_version_data vers = { 0 };
+ unsigned int tee_file_index = 0;
+ unsigned int ts_tee_dev_index = 0;
+ char path[16];
+ int rc = -1;
+ int fd = -1;
+
+ for (tee_file_index = 0; tee_file_index < MAX_TEE_DEV_NUM && ts_tee_dev_index < count;
+ tee_file_index++) {
+ snprintf(path, sizeof(path), "/dev/tee%u", tee_file_index);
+
+ fd = open(path, O_RDWR);
+ if (fd < 0)
+ continue;
+
+ memset(&vers, 0, sizeof(vers));
+
+ rc = ioctl(fd, TEE_IOC_VERSION, &vers);
+ close(fd);
+
+ if (!rc && vers.impl_id == TEE_IMPL_ID_TSTEE) {
+ ts_tee_devs[ts_tee_dev_index].endpoint_id = vers.impl_caps;
+ memcpy(ts_tee_devs[ts_tee_dev_index].path, path, sizeof(path));
+ ts_tee_dev_index++;
+ }
+ }
+}
+
+rpc_status_t ts_rpc_caller_linux_init(struct rpc_caller_interface *rpc_caller)
+{
+ struct ts_rpc_caller_linux_context *context = NULL;
+
+ if (!rpc_caller || rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (!ts_tee_drv_check_version())
+ return RPC_ERROR_INTERNAL;
+
+ context = (struct ts_rpc_caller_linux_context *)calloc(
+ 1, sizeof(struct ts_rpc_caller_linux_context));
+ if (!context)
+ return RPC_ERROR_INTERNAL;
+
+ context->fd = -1;
+ context->session_id = INVALID_SESS_ID;
+
+ rpc_caller->context = context;
+ rpc_caller->open_session = open_session;
+ rpc_caller->find_and_open_session = find_and_open_session;
+ rpc_caller->close_session = close_session;
+ rpc_caller->create_shared_memory = create_shared_memory;
+ rpc_caller->release_shared_memory = release_shared_memory;
+ rpc_caller->call = call;
+
+ ts_tee_drv_discover(context->ts_tee_devs, ARRAY_SIZE(context->ts_tee_devs));
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t ts_rpc_caller_linux_deinit(struct rpc_caller_interface *rpc_caller)
+{
+ struct ts_rpc_caller_linux_context *caller = NULL;
+
+ if (!rpc_caller || !rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ caller = (struct ts_rpc_caller_linux_context *)rpc_caller->context;
+
+ if (caller->session_id != INVALID_SESS_ID) {
+ close_session(rpc_caller);
+ caller->session_id = INVALID_SESS_ID;
+ }
+
+ if (caller->fd >= 0) {
+ close(caller->fd);
+ caller->fd = -1;
+ }
+
+ free(rpc_caller->context);
+
+ return RPC_SUCCESS;
+}
diff --git a/components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.h b/components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.h
new file mode 100644
index 000000000..26c6ce84a
--- /dev/null
+++ b/components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_RPC_CALLER_LINUX_H
+#define TS_RPC_CALLER_LINUX_H
+
+#include "components/rpc/common/caller/rpc_caller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+RPC_CALLER_EXPORTED
+rpc_status_t ts_rpc_caller_linux_init(struct rpc_caller_interface *rpc_caller);
+
+RPC_CALLER_EXPORTED
+rpc_status_t ts_rpc_caller_linux_deinit(struct rpc_caller_interface *rpc_caller);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TS_RPC_CALLER_LINUX_H */
diff --git a/components/rpc/ts_rpc/caller/sp/component.cmake b/components/rpc/ts_rpc/caller/sp/component.cmake
new file mode 100644
index 000000000..504720203
--- /dev/null
+++ b/components/rpc/ts_rpc/caller/sp/component.cmake
@@ -0,0 +1,18 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+ "${CMAKE_CURRENT_LIST_DIR}/ts_rpc_caller_sp.h"
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ts_rpc_caller_sp.c"
+ )
diff --git a/components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.c b/components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.c
new file mode 100644
index 000000000..ffa3d9b41
--- /dev/null
+++ b/components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "ts_rpc_caller_sp.h"
+#include <sp_memory_management.h>
+#include <sp_messaging.h>
+#include <string.h>
+#include <malloc.h>
+#include <ffa_api.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <trace.h>
+
+#ifndef MAX_RPC_ENDPOINT_NUM
+#define MAX_RPC_ENDPOINT_NUM ((uint8_t)(16))
+#endif /* MAX_RPC_ENDPOINT_NUM */
+
+#ifndef MAX_SHM_NUM
+#define MAX_SHM_NUM ((uint8_t)(16))
+#endif /* MAX_SHM_NUM */
+
+static const struct sp_uuid ts_ffa_uuid = {
+ .uuid = { 0xbd, 0xcd, 0x76, 0xd7, 0x82, 0x5e, 0x47, 0x51,
+ 0x96, 0x3b, 0x86, 0xd4, 0xf8, 0x49, 0x43, 0xac}
+};
+
+struct ts_rpc_caller_sp_context {
+ uint16_t own_id;
+ uint16_t endpoint_id;
+ uint8_t interface_id;
+ struct rpc_caller_shared_memory shared_memories[MAX_SHM_NUM];
+ bool has_opened_session;
+};
+
+static struct rpc_caller_shared_memory *find_shared_memory_descriptor(
+ struct ts_rpc_caller_sp_context *context, uint64_t id)
+{
+ size_t i = 0;
+
+ for (i = 0; i < MAX_SHM_NUM; i++) {
+ if (context->shared_memories[i].id == id)
+ return &context->shared_memories[i];
+ }
+
+ return NULL;
+}
+
+rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid, uint16_t endpoint_id)
+{
+ struct ts_rpc_caller_sp_context *this_context = (struct ts_rpc_caller_sp_context *)context;
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+ struct sp_msg req = { 0 };
+ struct sp_msg resp = { 0 };
+ uint8_t interface_id = 0;
+
+ if (!context || !service_uuid) {
+ EMSG("invalid arguments");
+ status = RPC_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ if (this_context->has_opened_session) {
+ EMSG("the session is already open");
+ status = RPC_ERROR_INVALID_STATE;
+ goto out;
+ }
+
+ if (endpoint_id == this_context->own_id) {
+ EMSG("cannot open RPC session to self");
+ status = RPC_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ req.source_id = this_context->own_id;
+ req.destination_id = endpoint_id;
+ req.is_64bit_message = false;
+
+ ts_rpc_abi_set_management_interface_id(req.args.args32);
+ ts_rpc_abi_set_opcode(req.args.args32, TS_RPC_ABI_MANAGEMENT_OPCODE_VERSION);
+
+ sp_res = sp_msg_send_direct_req(&req, &resp);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("sp_msg_send_direct_req(): error %"PRId32, sp_res);
+ goto out;
+ }
+
+ if (ts_rpc_abi_get_version(resp.args.args32) != TS_RPC_PROTOCOL_VERSION) {
+ EMSG("endpoint %"PRIu16" does not support protocol version %"PRIu32"",
+ endpoint_id, TS_RPC_PROTOCOL_VERSION);
+ goto out;
+ }
+
+ memset(req.args.args32, 0, sizeof(req.args.args32));
+ memset(resp.args.args32, 0, sizeof(resp.args.args32));
+
+ ts_rpc_abi_set_management_interface_id(req.args.args32);
+ ts_rpc_abi_set_opcode(req.args.args32, TS_RPC_ABI_MANAGEMENT_OPCODE_INTERFACE_ID_QUERY);
+ ts_rpc_abi_set_uuid(req.args.args32, service_uuid);
+
+ sp_res = sp_msg_send_direct_req(&req, &resp);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("sp_msg_send_direct_req(): error %"PRId32, sp_res);
+ goto out;
+ }
+
+ status = ts_rpc_abi_get_rpc_status(resp.args.args32);
+ if (status == RPC_SUCCESS) {
+ interface_id = ts_rpc_abi_get_queried_interface_id(resp.args.args32);
+
+ this_context->endpoint_id = endpoint_id;
+ this_context->interface_id = interface_id;
+ this_context->has_opened_session = true;
+ }
+
+out:
+ return status;
+}
+
+rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid)
+{
+ struct ts_rpc_caller_sp_context *this_context = (struct ts_rpc_caller_sp_context *)context;
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ ffa_result ffa_res = FFA_INVALID_PARAMETERS;
+ rpc_status_t status = RPC_SUCCESS;
+ uint32_t rpc_endpoint_count = MAX_RPC_ENDPOINT_NUM;
+ struct sp_partition_info rpc_endpoints[MAX_RPC_ENDPOINT_NUM] = {0};
+ uint32_t i = 0;
+
+ if (!context || !service_uuid) {
+ EMSG("invalid arguments");
+ return RPC_ERROR_INVALID_VALUE;
+ }
+
+ if (this_context->has_opened_session) {
+ EMSG("the session is already open");
+ return RPC_ERROR_INVALID_STATE;
+ }
+
+ sp_res = sp_discovery_partition_info_get(&ts_ffa_uuid, rpc_endpoints, &rpc_endpoint_count);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("sp_discovery_partition_info_get(): error %"PRId32, sp_res);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ ffa_res = ffa_rx_release();
+ if (ffa_res != FFA_OK) {
+ EMSG("ffa_rx_release(): error %"PRId32, ffa_res);
+ return 0;
+ }
+
+ for (i = 0; i < rpc_endpoint_count; i++) {
+ if (rpc_endpoints[i].partition_id == this_context->own_id)
+ continue;
+
+ status = open_session(context, service_uuid, rpc_endpoints[i].partition_id);
+
+ if (status == RPC_SUCCESS)
+ return RPC_SUCCESS;
+ }
+
+ EMSG("no SP found supporting protocol version %"PRIu32" and the requested service",
+ TS_RPC_PROTOCOL_VERSION);
+ return RPC_ERROR_INTERNAL;
+}
+
+rpc_status_t create_shared_memory(void *context, size_t size,
+ struct rpc_caller_shared_memory *shared_memory)
+{
+ struct ts_rpc_caller_sp_context *this_context = (struct ts_rpc_caller_sp_context *)context;
+ sp_result sp_res = SP_RESULT_OK;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+ struct sp_msg req = { 0 };
+ struct sp_msg resp = { 0 };
+
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_access_descriptor acc_desc = { 0 };
+ struct sp_memory_region region = { 0 };
+
+ uint64_t handle = 0;
+ void *buffer = NULL;
+ struct rpc_caller_shared_memory *stored_shared_memory_desc = NULL;
+
+ if (!context || !shared_memory) {
+ EMSG("invalid arguments");
+ status = RPC_ERROR_INVALID_VALUE;
+ goto err;
+ }
+
+ if (!this_context->has_opened_session) {
+ EMSG("session should be opened before creating shared memory");
+ status = RPC_ERROR_INVALID_STATE;
+ goto err;
+ }
+
+ if (size == 0) {
+ shared_memory->buffer = NULL;
+ shared_memory->size = 0;
+ shared_memory->id = FFA_MEM_HANDLE_INVALID;
+
+ return RPC_SUCCESS;
+ }
+
+ stored_shared_memory_desc = find_shared_memory_descriptor(this_context,
+ FFA_MEM_HANDLE_INVALID);
+ if (!stored_shared_memory_desc) {
+ status = RPC_ERROR_INTERNAL;
+ EMSG("cannot find empty shared memory descriptor");
+ goto err;
+ }
+
+ size = ROUNDUP(size, FFA_MEM_TRANSACTION_PAGE_SIZE);
+ buffer = memalign(FFA_MEM_TRANSACTION_PAGE_SIZE, size);
+ if (!buffer) {
+ EMSG("memalign(): failed to allocate %lu bytes with %"PRIu32" alignment", size,
+ FFA_MEM_TRANSACTION_PAGE_SIZE);
+ status = RPC_ERROR_INTERNAL;
+ goto err;
+ }
+ memset(buffer, 0, size);
+
+ desc.sender_id = this_context->own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability = sp_cacheability_write_back;
+ desc.mem_region_attr.normal_memory.shareability = sp_shareability_inner_shareable;
+
+ acc_desc.data_access = sp_data_access_read_write;
+ acc_desc.instruction_access = sp_instruction_access_not_specified;
+ acc_desc.receiver_id = this_context->endpoint_id;
+
+ region.address = buffer;
+ region.page_count = (uint32_t)ROUNDUP_DIV(size, FFA_MEM_TRANSACTION_PAGE_SIZE);
+
+ sp_res = sp_memory_share(&desc, &acc_desc, 1, &region, 1, &handle);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("sp_memory_share(): error %"PRId32, sp_res);
+ status = RPC_ERROR_INTERNAL;
+ goto err;
+ }
+
+ req.source_id = this_context->own_id;
+ req.destination_id = this_context->endpoint_id;
+ req.is_64bit_message = false;
+
+ ts_rpc_abi_set_management_interface_id(req.args.args32);
+ ts_rpc_abi_set_opcode(req.args.args32, TS_RPC_ABI_MANAGEMENT_OPCODE_MEMORY_RETRIEVE);
+ ts_rpc_abi_set_memory_handle(req.args.args32, handle);
+ ts_rpc_abi_set_memory_tag(req.args.args32, 0);
+
+ sp_res = sp_msg_send_direct_req(&req, &resp);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("sp_msg_send_direct_req(): error %"PRId32, sp_res);
+ status = RPC_ERROR_INTERNAL;
+ goto err;
+ }
+
+ status = ts_rpc_abi_get_rpc_status(resp.args.args32);
+ if (status != RPC_SUCCESS) {
+ EMSG("RPC endpoint error: %"PRId32, status);
+
+ sp_res = sp_memory_reclaim(handle, 0);
+ if (sp_res != SP_RESULT_OK)
+ EMSG("sp_memory_reclaim(): error %"PRId32, sp_res);
+
+ status = RPC_ERROR_INTERNAL;
+ goto err;
+ }
+
+ shared_memory->id = handle;
+ shared_memory->buffer = buffer;
+ shared_memory->size = size;
+
+ *stored_shared_memory_desc = *shared_memory;
+
+ return RPC_SUCCESS;
+
+err:
+ if (buffer)
+ free(buffer);
+ return status;
+}
+
+rpc_status_t release_shared_memory(void *context, struct rpc_caller_shared_memory *shared_memory)
+{
+ struct ts_rpc_caller_sp_context *this_context = (struct ts_rpc_caller_sp_context *)context;
+ sp_result sp_res = SP_RESULT_OK;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+ struct sp_msg req = { 0 };
+ struct sp_msg resp = { 0 };
+
+ struct rpc_caller_shared_memory *to_release = NULL;
+
+ if (!context || !shared_memory) {
+ EMSG("invalid arguments");
+ return RPC_ERROR_INVALID_VALUE;
+ }
+
+ if (shared_memory->id == FFA_MEM_HANDLE_INVALID)
+ return RPC_SUCCESS;
+
+ to_release = find_shared_memory_descriptor(this_context, shared_memory->id);
+ if (!to_release) {
+ EMSG("cannot find shared memory with specified handle");
+ return RPC_ERROR_INTERNAL;
+ }
+
+ req.source_id = this_context->own_id;
+ req.destination_id = this_context->endpoint_id;
+ req.is_64bit_message = false;
+
+ ts_rpc_abi_set_management_interface_id(req.args.args32);
+ ts_rpc_abi_set_opcode(req.args.args32, TS_RPC_ABI_MANAGEMENT_OPCODE_MEMORY_RELINQUISH);
+ ts_rpc_abi_set_memory_handle(req.args.args32, to_release->id);
+
+ sp_res = sp_msg_send_direct_req(&req, &resp);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("sp_msg_send_direct_req(): error %"PRId32, sp_res);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ status = ts_rpc_abi_get_rpc_status(resp.args.args32);
+ if (status != RPC_SUCCESS) {
+ /*
+ * The RPC endpoint failed to relinquish the shared memory but
+ * still worth trying to reclaim the memory beside emitting an
+ * error message.
+ */
+ EMSG("RPC endpoint error %"PRId32, status);
+ }
+
+ sp_res = sp_memory_reclaim(to_release->id, 0);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("sp_memory_reclaim(): error %"PRId32, sp_res);
+ return RPC_ERROR_INTERNAL;
+ }
+
+ /*
+ * Only remove shared memory entry and free it if both relinquish AND reclaim were
+ * successful.
+ */
+ if (status == RPC_SUCCESS) {
+ free(to_release->buffer);
+
+ to_release->id = FFA_MEM_HANDLE_INVALID;
+ to_release->buffer = NULL;
+ to_release->size = 0;
+ }
+
+ return status;
+}
+
+rpc_status_t call(void *context, uint16_t opcode, struct rpc_caller_shared_memory *shared_memory,
+ size_t request_length, size_t *response_length, service_status_t *service_status)
+{
+
+ struct ts_rpc_caller_sp_context *this_context = (struct ts_rpc_caller_sp_context *)context;
+ sp_result sp_res = SP_RESULT_OK;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+ struct sp_msg req = { 0 };
+ struct sp_msg resp = { 0 };
+
+ if (!context || !shared_memory || !response_length || !service_status) {
+ EMSG("invalid arguments");
+ status = RPC_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ if (!this_context->has_opened_session) {
+ EMSG("session should be opened before calling a service");
+ status = RPC_ERROR_INVALID_STATE;
+ goto out;
+ }
+
+ if (shared_memory->id != FFA_MEM_HANDLE_INVALID) {
+ /* Checking if the shared memory was allocated by us */
+ struct rpc_caller_shared_memory *stored_shared_memory = NULL;
+
+ stored_shared_memory = find_shared_memory_descriptor(this_context,
+ shared_memory->id);
+ if (!stored_shared_memory) {
+ EMSG("cannot find shared memory with specified handle");
+ status = RPC_ERROR_INTERNAL;
+ goto out;
+ }
+ } else {
+ /* Call with no shared memory, the request length must be 0 */
+ if (request_length != 0) {
+ status = RPC_ERROR_INVALID_VALUE;
+ goto out;
+ }
+ }
+
+ req.source_id = this_context->own_id;
+ req.destination_id = this_context->endpoint_id;
+ req.is_64bit_message = false;
+
+ ts_rpc_abi_set_interface_id(req.args.args32, this_context->interface_id);
+ ts_rpc_abi_set_opcode(req.args.args32, opcode);
+ ts_rpc_abi_set_memory_handle(req.args.args32, shared_memory->id);
+ ts_rpc_abi_set_request_length(req.args.args32, request_length);
+ ts_rpc_abi_set_client_id(req.args.args32, 0);
+
+ sp_res = sp_msg_send_direct_req(&req, &resp);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("sp_msg_send_direct_req(): error %"PRId32, sp_res);
+ status = RPC_ERROR_INTERNAL;
+ goto out;
+ }
+
+ status = ts_rpc_abi_get_rpc_status(resp.args.args32);
+ if (status != RPC_SUCCESS) {
+ EMSG("RPC endpoint error %"PRId32, status);
+ goto out;
+ }
+
+ *service_status = ts_rpc_abi_get_service_status(resp.args.args32);
+ *response_length = ts_rpc_abi_get_response_length(resp.args.args32);
+
+out:
+ return status;
+}
+
+rpc_status_t close_session(void *context)
+{
+ struct ts_rpc_caller_sp_context *this_context = (struct ts_rpc_caller_sp_context *)context;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ uint8_t i = 0;
+
+ if (!context) {
+ EMSG("invalid arguments");
+ return RPC_ERROR_INVALID_VALUE;
+ }
+
+ if (!this_context->has_opened_session) {
+ EMSG("session is already closed");
+ status = RPC_ERROR_INVALID_STATE;
+ goto out;
+ }
+
+ for (i = 0; i < MAX_SHM_NUM; i++) {
+ if (this_context->shared_memories[i].id != FFA_MEM_HANDLE_INVALID) {
+ status = release_shared_memory(context, &this_context->shared_memories[i]);
+
+ if (status != RPC_SUCCESS) {
+ EMSG("failed to release shared memory with handle %"PRIu64"",
+ this_context->shared_memories[i].id);
+ goto out;
+ }
+ }
+ }
+
+ this_context->endpoint_id = 0;
+ this_context->interface_id = 0;
+ this_context->has_opened_session = false;
+
+ return RPC_SUCCESS;
+
+out:
+ return status;
+}
+
+rpc_status_t ts_rpc_caller_sp_init(struct rpc_caller_interface *rpc_caller)
+{
+ struct ts_rpc_caller_sp_context *context = NULL;
+ uint16_t own_id;
+ uint8_t i = 0;
+
+ if (!rpc_caller || rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (sp_discovery_own_id_get(&own_id) != SP_RESULT_OK)
+ return RPC_ERROR_INTERNAL;
+
+ context = (struct ts_rpc_caller_sp_context *)
+ calloc(1, sizeof(struct ts_rpc_caller_sp_context));
+ if (!context)
+ return RPC_ERROR_INTERNAL;
+
+ for (i = 0; i < MAX_SHM_NUM; i++)
+ context->shared_memories[i].id = FFA_MEM_HANDLE_INVALID;
+
+ context->own_id = own_id;
+
+ rpc_caller->context = context;
+ rpc_caller->open_session = open_session;
+ rpc_caller->find_and_open_session = find_and_open_session;
+ rpc_caller->close_session = close_session;
+ rpc_caller->create_shared_memory = create_shared_memory;
+ rpc_caller->release_shared_memory = release_shared_memory;
+ rpc_caller->call = call;
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t ts_rpc_caller_sp_deinit(struct rpc_caller_interface *rpc_caller)
+{
+ struct ts_rpc_caller_sp_context *this_context =
+ (struct ts_rpc_caller_sp_context *)rpc_caller->context;
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ if (!rpc_caller || !rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ if (!this_context->has_opened_session) {
+ status = rpc_caller_close_session(rpc_caller);
+ if (status != RPC_SUCCESS) {
+ EMSG("failed to close session");
+ return RPC_ERROR_INTERNAL;
+ }
+ }
+
+ free(rpc_caller->context);
+ rpc_caller->context = NULL;
+
+ return RPC_SUCCESS;
+}
diff --git a/components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.h b/components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.h
new file mode 100644
index 000000000..07c51b521
--- /dev/null
+++ b/components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_RPC_CALLER_SP_H
+#define TS_RPC_CALLER_SP_H
+
+#include "rpc_status.h"
+#include "rpc_uuid.h"
+#include "sp_discovery.h"
+#include <common/uuid/uuid.h>
+#include "components/rpc/ts_rpc/common/ts_rpc_abi.h"
+#include "components/rpc/common/caller/rpc_caller.h"
+#include "util.h"
+
+/* Protocol version*/
+#define TS_RPC_PROTOCOL_VERSION (1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+rpc_status_t ts_rpc_caller_sp_init(struct rpc_caller_interface *rpc_caller);
+
+rpc_status_t ts_rpc_caller_sp_deinit(struct rpc_caller_interface *rpc_caller);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TS_RPC_CALLER_SP_H */
diff --git a/components/rpc/ts_rpc/common/component.cmake b/components/rpc/ts_rpc/common/component.cmake
new file mode 100644
index 000000000..71d4e8e57
--- /dev/null
+++ b/components/rpc/ts_rpc/common/component.cmake
@@ -0,0 +1,18 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+ "${CMAKE_CURRENT_LIST_DIR}/ts_rpc_abi.h"
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ts_rpc_abi.c"
+ )
diff --git a/components/rpc/ts_rpc/common/test/test_ts_rpc_abi.cpp b/components/rpc/ts_rpc/common/test/test_ts_rpc_abi.cpp
new file mode 100644
index 000000000..463792b0d
--- /dev/null
+++ b/components/rpc/ts_rpc/common/test/test_ts_rpc_abi.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "../ts_rpc_abi.h"
+#include <stdint.h>
+#include <string.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(ts_rpc_abi) {
+ TEST_SETUP() {
+ memset(regs, 0x00, sizeof(regs));
+ }
+
+ void set_regs(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4)
+ {
+ regs[0] = a0;
+ regs[1] = a1;
+ regs[2] = a2;
+ regs[3] = a3;
+ regs[4] = a4;
+ }
+
+ void check_regs(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4)
+ {
+ UNSIGNED_LONGS_EQUAL(a0, regs[0]);
+ UNSIGNED_LONGS_EQUAL(a1, regs[1]);
+ UNSIGNED_LONGS_EQUAL(a2, regs[2]);
+ UNSIGNED_LONGS_EQUAL(a3, regs[3]);
+ UNSIGNED_LONGS_EQUAL(a4, regs[4]);
+ }
+
+ uint32_t regs[5];
+};
+
+TEST(ts_rpc_abi, flags)
+{
+ const uint8_t flags = 0x3f;
+
+ ts_rpc_abi_set_flags(regs, flags);
+ check_regs(0x3f000000, 0, 0, 0, 0);
+
+ UNSIGNED_LONGS_EQUAL(flags, ts_rpc_abi_get_flags(regs));
+}
+
+TEST(ts_rpc_abi, interface_id)
+{
+ const uint8_t interface_id = 0xa5;
+
+ ts_rpc_abi_set_interface_id(regs, interface_id);
+ check_regs(0x00a50000, 0, 0, 0, 0);
+
+ UNSIGNED_LONGS_EQUAL(interface_id, ts_rpc_abi_get_interface_id(regs));
+}
+
+TEST(ts_rpc_abi, management_interface_id)
+{
+ CHECK_FALSE(ts_rpc_abi_is_management_interface_id(regs));
+
+ ts_rpc_abi_set_management_interface_id(regs);
+ check_regs(0x00ff0000, 0, 0, 0, 0);
+
+ CHECK_TRUE(ts_rpc_abi_is_management_interface_id(regs));
+}
+
+TEST(ts_rpc_abi, opcode)
+{
+ const uint16_t opcode = 0x8765;
+
+ ts_rpc_abi_set_opcode(regs, 0x8765);
+ check_regs(0x00008765, 0, 0, 0, 0);
+
+ UNSIGNED_LONGS_EQUAL(0x8765, ts_rpc_abi_get_opcode(regs));
+}
+
+TEST(ts_rpc_abi, copy_control_reg)
+{
+ uint32_t source_regs[5] = { 0xfedcba98, 0, 0, 0, 0 };
+
+ ts_rpc_abi_copy_control_reg(regs, source_regs);
+
+ check_regs(0xfedcba98, 0, 0, 0, 0);
+}
+
+TEST(ts_rpc_abi, version)
+{
+ const uint32_t version = 0x98765432;
+
+ ts_rpc_abi_set_version(regs, version);
+ check_regs(0, version, 0, 0, 0);
+
+ UNSIGNED_LONGS_EQUAL(version, ts_rpc_abi_get_version(regs));
+
+}
+
+TEST(ts_rpc_abi, memory_handle)
+{
+ const uint64_t handle = 0xfedcba9876543210;
+
+ ts_rpc_abi_set_memory_handle(regs, handle);
+ check_regs(0, 0x76543210, 0xfedcba98, 0, 0);
+
+ UNSIGNED_LONGLONGS_EQUAL(handle, ts_rpc_abi_get_memory_handle(regs));
+}
+
+TEST(ts_rpc_abi, memory_tag)
+{
+ const uint64_t tag = 0xfedcba9876543210;
+
+ ts_rpc_abi_set_memory_tag(regs, tag);
+ check_regs(0, 0, 0, 0x76543210, 0xfedcba98);
+
+ UNSIGNED_LONGLONGS_EQUAL(tag, ts_rpc_abi_get_memory_tag(regs));
+}
+
+TEST(ts_rpc_abi, rpc_status)
+{
+ const uint32_t rpc_status = 0x89abcdef;
+
+ ts_rpc_abi_set_rpc_status(regs, rpc_status);
+ check_regs(0, rpc_status, 0, 0, 0);
+
+ UNSIGNED_LONGS_EQUAL(rpc_status, ts_rpc_abi_get_rpc_status(regs));
+}
+
+TEST(ts_rpc_abi, service_status)
+{
+ const uint32_t service_status = 0x89abcdef;
+
+ ts_rpc_abi_set_service_status(regs, service_status);
+ check_regs(0, 0, service_status, 0, 0);
+
+ UNSIGNED_LONGS_EQUAL(service_status, ts_rpc_abi_get_service_status(regs));
+}
+
+TEST(ts_rpc_abi, uuid)
+{
+ const struct rpc_uuid expected = {
+ .uuid = { 0xf0, 0x33, 0xbe, 0x6d, 0x6c, 0xc4, 0x47, 0x38,
+ 0x88, 0xfd, 0xdd, 0x44, 0xac, 0x56, 0x2b, 0x69}
+ };
+ struct rpc_uuid actual = { 0 };
+
+ ts_rpc_abi_set_uuid(regs, &expected);
+ check_regs(0, 0x6dbe33f0, 0x3847c46c, 0x44ddfd88, 0x692b56ac);
+
+ ts_rpc_abi_get_uuid(regs, &actual);
+ MEMCMP_EQUAL(expected.uuid, actual.uuid, sizeof(expected));
+}
+
+TEST(ts_rpc_abi, queried_interface_id)
+{
+ const uint8_t interface_id = 0xa5;
+
+ ts_rpc_abi_set_queried_interface_id(regs, interface_id);
+ check_regs(0, 0, interface_id, 0, 0);
+
+ UNSIGNED_LONGS_EQUAL(interface_id, ts_rpc_abi_get_queried_interface_id(regs));
+}
+
+TEST(ts_rpc_abi, request_length)
+{
+ const uint32_t length = 0x12345678;
+
+ ts_rpc_abi_set_request_length(regs, length);
+ check_regs(0, 0, 0, length, 0);
+
+ UNSIGNED_LONGS_EQUAL(length, ts_rpc_abi_get_request_length(regs));
+}
+
+TEST(ts_rpc_abi, client_id)
+{
+ const uint32_t client_id = 0xabcdef01;
+
+ ts_rpc_abi_set_client_id(regs, client_id);
+ check_regs(0, 0, 0, 0, client_id);
+
+ UNSIGNED_LONGS_EQUAL(client_id, ts_rpc_abi_get_client_id(regs));
+}
+
+TEST(ts_rpc_abi, response_length)
+{
+ const uint32_t length = 0x12345678;
+
+ ts_rpc_abi_set_response_length(regs, length);
+ check_regs(0, 0, 0, length, 0);
+
+ UNSIGNED_LONGS_EQUAL(length, ts_rpc_abi_get_response_length(regs));
+}
diff --git a/components/rpc/ts_rpc/common/ts_rpc_abi.c b/components/rpc/ts_rpc/common/ts_rpc_abi.c
new file mode 100644
index 000000000..674e668dd
--- /dev/null
+++ b/components/rpc/ts_rpc/common/ts_rpc_abi.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "ts_rpc_abi.h"
+#include <string.h>
+
+#define TS_RPC_CONTROL_REG (0)
+
+#define TS_RPC_FLAGS_REG (0)
+#define TS_RPC_FLAGS_SHIFT (24)
+#define TS_RPC_FLAGS_MASK (0x3f)
+
+#define TS_RPC_INTERFACE_ID_REG (0)
+#define TS_RPC_INTERFACE_ID_SHIFT (16)
+#define TS_RPC_INTERFACE_ID_MASK (0xff)
+
+#define TS_RPC_MANAGEMENT_INTERFACE_ID (0xff)
+
+#define TS_RPC_OPCODE_REG (0)
+#define TS_RPC_OPCODE_SHIFT (0)
+#define TS_RPC_OPCODE_MASK (0xffff)
+
+#define TS_RPC_VERSION_REG (1)
+#define TS_RPC_MEMORY_HANDLE_LSW_REG (1)
+#define TS_RPC_MEMORY_HANDLE_MSW_REG (2)
+#define TS_RPC_MEMORY_TAG_LSW_REG (3)
+#define TS_RPC_MEMORY_TAG_MSW_REG (4)
+#define TS_RPC_RPC_STATUS_REG (1)
+#define TS_RPC_SERVICE_STATUS_REG (2)
+#define TS_RPC_UUID_START_REG (1)
+
+#define TS_RPC_QUERIED_INTERFACE_ID_REG (2)
+#define TS_RPC_QUERIED_INTERFACE_ID_SHIFT (0)
+#define TS_RPC_QUERIED_INTERFACE_ID_MASK (0xff)
+
+#define TS_RPC_REQUEST_LENGTH_REG (3)
+#define TS_RPC_CLIENT_ID_REG (4)
+#define TS_RPC_RESPONSE_LENGTH_REG (3)
+#define TS_RPC_FAST_REQUEST_DATA_START_REG (1)
+#define TS_RPC_FAST_RESPONSE_DATA_START_REG (2)
+
+static uint32_t get_field(const uint32_t regs[5], uint32_t reg, uint32_t shift, uint32_t mask)
+{
+ return (regs[reg] >> shift) & mask;
+}
+
+static void set_field(uint32_t regs[5], uint32_t reg, uint32_t shift, uint32_t mask,
+ uint32_t value)
+{
+ regs[reg] &= ~(mask << shift);
+ regs[reg] |= (value & mask) << shift;
+}
+
+uint8_t ts_rpc_abi_get_flags(const uint32_t regs[5])
+{
+ return get_field(regs, TS_RPC_FLAGS_REG, TS_RPC_FLAGS_SHIFT, TS_RPC_FLAGS_MASK);
+}
+
+void ts_rpc_abi_set_flags(uint32_t regs[5], uint8_t flags)
+{
+ set_field(regs, TS_RPC_FLAGS_REG, TS_RPC_FLAGS_SHIFT, TS_RPC_FLAGS_MASK, flags);
+}
+
+uint8_t ts_rpc_abi_get_interface_id(const uint32_t regs[5])
+{
+ return get_field(regs, TS_RPC_INTERFACE_ID_REG, TS_RPC_INTERFACE_ID_SHIFT,
+ TS_RPC_INTERFACE_ID_MASK);
+}
+
+void ts_rpc_abi_set_interface_id(uint32_t regs[5], uint8_t interface_id)
+{
+ set_field(regs, TS_RPC_INTERFACE_ID_REG, TS_RPC_INTERFACE_ID_SHIFT,
+ TS_RPC_INTERFACE_ID_MASK, interface_id);
+}
+
+bool ts_rpc_abi_is_management_interface_id(const uint32_t regs[5])
+{
+ return ts_rpc_abi_get_interface_id(regs) == TS_RPC_MANAGEMENT_INTERFACE_ID;
+}
+
+void ts_rpc_abi_set_management_interface_id(uint32_t regs[5])
+{
+ ts_rpc_abi_set_interface_id(regs, TS_RPC_MANAGEMENT_INTERFACE_ID);
+}
+
+uint16_t ts_rpc_abi_get_opcode(const uint32_t regs[5])
+{
+ return get_field(regs, TS_RPC_OPCODE_REG, TS_RPC_OPCODE_SHIFT, TS_RPC_OPCODE_MASK);
+}
+
+void ts_rpc_abi_set_opcode(uint32_t regs[5], uint16_t opcode)
+{
+ set_field(regs, TS_RPC_OPCODE_REG, TS_RPC_OPCODE_SHIFT, TS_RPC_OPCODE_MASK, opcode);
+}
+
+void ts_rpc_abi_copy_control_reg(uint32_t response_regs[5], const uint32_t request_regs[5])
+{
+ response_regs[TS_RPC_CONTROL_REG] = request_regs[TS_RPC_CONTROL_REG];
+}
+
+uint32_t ts_rpc_abi_get_version(const uint32_t regs[5])
+{
+ return regs[TS_RPC_VERSION_REG];
+}
+
+void ts_rpc_abi_set_version(uint32_t regs[5], uint32_t version)
+{
+ regs[TS_RPC_VERSION_REG] = version;
+}
+
+uint64_t ts_rpc_abi_get_memory_handle(const uint32_t regs[5])
+{
+ return (uint64_t)regs[TS_RPC_MEMORY_HANDLE_MSW_REG] << 32 |
+ regs[TS_RPC_MEMORY_HANDLE_LSW_REG];
+}
+
+void ts_rpc_abi_set_memory_handle(uint32_t regs[5], uint64_t handle)
+{
+ regs[TS_RPC_MEMORY_HANDLE_LSW_REG] = handle;
+ regs[TS_RPC_MEMORY_HANDLE_MSW_REG] = handle >> 32;
+}
+
+uint64_t ts_rpc_abi_get_memory_tag(const uint32_t regs[5])
+{
+ return (uint64_t)regs[TS_RPC_MEMORY_TAG_MSW_REG] << 32 | regs[TS_RPC_MEMORY_TAG_LSW_REG];
+}
+
+void ts_rpc_abi_set_memory_tag(uint32_t regs[5], uint64_t tag)
+{
+ regs[TS_RPC_MEMORY_TAG_LSW_REG] = tag;
+ regs[TS_RPC_MEMORY_TAG_MSW_REG] = tag >> 32;
+}
+
+uint32_t ts_rpc_abi_get_rpc_status(const uint32_t regs[5])
+{
+ return regs[TS_RPC_RPC_STATUS_REG];
+}
+
+void ts_rpc_abi_set_rpc_status(uint32_t regs[5], uint32_t status)
+{
+ regs[TS_RPC_RPC_STATUS_REG] = status;
+}
+
+uint32_t ts_rpc_abi_get_service_status(const uint32_t regs[5])
+{
+ return regs[TS_RPC_SERVICE_STATUS_REG];
+}
+
+void ts_rpc_abi_set_service_status(uint32_t regs[5], uint32_t status)
+{
+ regs[TS_RPC_SERVICE_STATUS_REG] = status;
+}
+
+void ts_rpc_abi_get_uuid(const uint32_t regs[5], struct rpc_uuid *uuid)
+{
+ memcpy(uuid, &regs[TS_RPC_UUID_START_REG], sizeof(*uuid));
+}
+
+void ts_rpc_abi_set_uuid(uint32_t regs[5], const struct rpc_uuid *uuid)
+{
+ memcpy(&regs[TS_RPC_UUID_START_REG], uuid, sizeof(*uuid));
+}
+
+uint8_t ts_rpc_abi_get_queried_interface_id(const uint32_t regs[5])
+{
+ return get_field(regs, TS_RPC_QUERIED_INTERFACE_ID_REG, TS_RPC_QUERIED_INTERFACE_ID_SHIFT,
+ TS_RPC_QUERIED_INTERFACE_ID_MASK);
+}
+
+void ts_rpc_abi_set_queried_interface_id(uint32_t regs[5], uint8_t interface_id)
+{
+ set_field(regs, TS_RPC_QUERIED_INTERFACE_ID_REG, TS_RPC_QUERIED_INTERFACE_ID_SHIFT,
+ TS_RPC_QUERIED_INTERFACE_ID_MASK, interface_id);
+}
+
+uint32_t ts_rpc_abi_get_request_length(const uint32_t regs[5])
+{
+ return regs[TS_RPC_REQUEST_LENGTH_REG];
+}
+
+void ts_rpc_abi_set_request_length(uint32_t regs[5], uint32_t length)
+{
+ regs[TS_RPC_REQUEST_LENGTH_REG] = length;
+}
+
+uint32_t ts_rpc_abi_get_client_id(const uint32_t regs[5])
+{
+ return regs[TS_RPC_CLIENT_ID_REG];
+}
+
+void ts_rpc_abi_set_client_id(uint32_t regs[5], uint32_t client_id)
+{
+ regs[TS_RPC_CLIENT_ID_REG] = client_id;
+}
+
+uint32_t ts_rpc_abi_get_response_length(const uint32_t regs[5])
+{
+ return regs[TS_RPC_RESPONSE_LENGTH_REG];
+}
+
+void ts_rpc_abi_set_response_length(uint32_t regs[5], uint32_t length)
+{
+ regs[TS_RPC_RESPONSE_LENGTH_REG] = length;
+}
diff --git a/components/rpc/ts_rpc/common/ts_rpc_abi.h b/components/rpc/ts_rpc/common/ts_rpc_abi.h
new file mode 100644
index 000000000..8b0fa1c6a
--- /dev/null
+++ b/components/rpc/ts_rpc/common/ts_rpc_abi.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_RPC_ABI_H
+#define TS_RPC_ABI_H
+
+#include "rpc_uuid.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Trusted-services RPC ABI function
+ *
+ * This file contains getters and setters for TS ABI fields. They handle the five arg registers of
+ * the FF-A direct messages and extract or insert fields of suitable types.
+ */
+
+#define TS_RPC_ABI_FLAG_FAST_CALL (0x01)
+
+#define TS_RPC_ABI_MANAGEMENT_OPCODE_VERSION (0)
+#define TS_RPC_ABI_MANAGEMENT_OPCODE_MEMORY_RETRIEVE (1)
+#define TS_RPC_ABI_MANAGEMENT_OPCODE_MEMORY_RELINQUISH (2)
+#define TS_RPC_ABI_MANAGEMENT_OPCODE_INTERFACE_ID_QUERY (3)
+
+#define TS_RPC_ABI_VERSION_V1 (1)
+
+uint8_t ts_rpc_abi_get_flags(const uint32_t regs[5]);
+void ts_rpc_abi_set_flags(uint32_t regs[5], uint8_t flags);
+
+uint8_t ts_rpc_abi_get_interface_id(const uint32_t regs[5]);
+void ts_rpc_abi_set_interface_id(uint32_t regs[5], uint8_t interface_id);
+
+bool ts_rpc_abi_is_management_interface_id(const uint32_t regs[5]);
+void ts_rpc_abi_set_management_interface_id(uint32_t regs[5]);
+
+uint16_t ts_rpc_abi_get_opcode(const uint32_t regs[5]);
+void ts_rpc_abi_set_opcode(uint32_t regs[5], uint16_t interface_id);
+
+void ts_rpc_abi_copy_control_reg(uint32_t response_regs[5], const uint32_t request_regs[5]);
+
+uint32_t ts_rpc_abi_get_version(const uint32_t regs[5]);
+void ts_rpc_abi_set_version(uint32_t regs[5], uint32_t version);
+
+uint64_t ts_rpc_abi_get_memory_handle(const uint32_t regs[5]);
+void ts_rpc_abi_set_memory_handle(uint32_t regs[5], uint64_t handle);
+
+uint64_t ts_rpc_abi_get_memory_tag(const uint32_t regs[5]);
+void ts_rpc_abi_set_memory_tag(uint32_t regs[5], uint64_t tag);
+
+uint32_t ts_rpc_abi_get_rpc_status(const uint32_t regs[5]);
+void ts_rpc_abi_set_rpc_status(uint32_t regs[5], uint32_t status);
+
+uint32_t ts_rpc_abi_get_service_status(const uint32_t regs[5]);
+void ts_rpc_abi_set_service_status(uint32_t regs[5], uint32_t status);
+
+void ts_rpc_abi_get_uuid(const uint32_t regs[5], struct rpc_uuid *uuid);
+void ts_rpc_abi_set_uuid(uint32_t regs[5], const struct rpc_uuid *uuid);
+
+uint8_t ts_rpc_abi_get_queried_interface_id(const uint32_t regs[5]);
+void ts_rpc_abi_set_queried_interface_id(uint32_t regs[5], uint8_t interface_id);
+
+uint32_t ts_rpc_abi_get_request_length(const uint32_t regs[5]);
+void ts_rpc_abi_set_request_length(uint32_t regs[5], uint32_t length);
+
+uint32_t ts_rpc_abi_get_client_id(const uint32_t regs[5]);
+void ts_rpc_abi_set_client_id(uint32_t regs[5], uint32_t client_id);
+
+uint32_t ts_rpc_abi_get_response_length(const uint32_t regs[5]);
+void ts_rpc_abi_set_response_length(uint32_t regs[5], uint32_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TS_RPC_ABI_H */
diff --git a/components/rpc/ts_rpc/endpoint/sp/component.cmake b/components/rpc/ts_rpc/endpoint/sp/component.cmake
new file mode 100644
index 000000000..62d47ddc7
--- /dev/null
+++ b/components/rpc/ts_rpc/endpoint/sp/component.cmake
@@ -0,0 +1,18 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+ "${CMAKE_CURRENT_LIST_DIR}/ts_rpc_endpoint_sp.h"
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ts_rpc_endpoint_sp.c"
+ )
diff --git a/components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.c b/components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.c
new file mode 100644
index 000000000..d001158b6
--- /dev/null
+++ b/components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "ts_rpc_endpoint_sp.h"
+#include "sp_discovery.h"
+#include "sp_memory_management.h"
+#include "trace.h"
+#include <stdlib.h>
+#include <string.h>
+
+static const struct ts_rpc_shared_memory null_shared_memory = {
+ .owner_id = 0xffff, .handle = FFA_MEM_HANDLE_INVALID, .data = NULL, .size = 0, .used = true
+};
+
+static struct ts_rpc_shared_memory *find_free_shared_memory_descriptor(
+ struct ts_rpc_endpoint_sp *endpoint)
+{
+ struct ts_rpc_shared_memory *memory = endpoint->shared_memories;
+ struct ts_rpc_shared_memory *end = memory + endpoint->shared_memory_count;
+
+ for (; memory < end; memory++)
+ if (!memory->used)
+ return memory;
+
+ return NULL;
+}
+
+static struct ts_rpc_shared_memory *find_shared_memory_descriptor(
+ struct ts_rpc_endpoint_sp *endpoint, uint16_t owner_id, uint64_t handle)
+{
+ struct ts_rpc_shared_memory *memory = endpoint->shared_memories;
+ struct ts_rpc_shared_memory *end = memory + endpoint->shared_memory_count;
+
+ for (; memory < end; memory++)
+ if (memory->used && memory->owner_id == owner_id && memory->handle == handle)
+ return memory;
+
+ return NULL;
+}
+
+static rpc_status_t handle_memory_retrieve(struct ts_rpc_endpoint_sp *endpoint, uint16_t source_id,
+ uint64_t memory_handle, uint64_t memory_tag)
+{
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_access_descriptor acc_desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint32_t in_region_count = 0;
+ uint32_t out_region_count = 1;
+ struct ts_rpc_shared_memory *memory = NULL;
+
+ (void)memory_tag;
+
+ memory = find_free_shared_memory_descriptor(endpoint);
+ if (!memory) {
+ EMSG("No available shared memory slot");
+ return RPC_ERROR_NOT_FOUND;
+ }
+
+ desc.sender_id = source_id;
+ desc.memory_type = sp_memory_type_not_specified;
+ desc.flags.transaction_type = sp_memory_transaction_type_share;
+ acc_desc.receiver_id = endpoint->own_id;
+ acc_desc.data_access = sp_data_access_read_write;
+
+ sp_res = sp_memory_retrieve(&desc, &acc_desc, &region, in_region_count,
+ &out_region_count, memory_handle);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to retrieve memory: %d", sp_res);
+ return RPC_ERROR_TRANSPORT_LAYER;
+ }
+
+ memory->owner_id = source_id;
+ memory->handle = memory_handle;
+ memory->data = region.address;
+ memory->size = region.page_count * FFA_MEM_TRANSACTION_PAGE_SIZE;
+ memory->used = true;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t handle_memory_relinquish(struct ts_rpc_endpoint_sp *endpoint,
+ uint16_t source_id, uint64_t memory_handle)
+{
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ uint16_t endpoints[1] = { 0 };
+ uint32_t endpoint_count = 1;
+ struct sp_memory_transaction_flags flags = {
+ .zero_memory = false,
+ .operation_time_slicing = false,
+ };
+ struct ts_rpc_shared_memory *memory = NULL;
+
+ memory = find_shared_memory_descriptor(endpoint, source_id, memory_handle);
+ if (!memory) {
+ EMSG("Shared memory not found");
+ return RPC_ERROR_NOT_FOUND;
+ }
+
+ endpoints[0] = endpoint->own_id;
+
+ sp_res = sp_memory_relinquish(memory->handle, endpoints, endpoint_count, &flags);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to relinquish memory: %d", sp_res);
+ return RPC_ERROR_TRANSPORT_LAYER;
+ }
+
+ *memory = (struct ts_rpc_shared_memory){ 0 };
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t handle_interface_id_query(struct ts_rpc_endpoint_sp *endpoint,
+ const struct rpc_uuid *service_uuid,
+ uint8_t *interface_id)
+{
+ size_t i = 0;
+
+ for (i = 0; i < endpoint->service_count; i++) {
+ if (endpoint->services[i] &&
+ rpc_uuid_equal(service_uuid, &endpoint->services[i]->uuid)) {
+ *interface_id = i;
+ return RPC_SUCCESS;
+ }
+ }
+
+ *interface_id = 0;
+ return RPC_ERROR_NOT_FOUND;
+}
+
+static void handle_management_interface(struct ts_rpc_endpoint_sp *endpoint, uint16_t source_id,
+ const uint32_t request[5], uint32_t response[5])
+{
+ uint16_t opcode = ts_rpc_abi_get_opcode(request);
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ switch (opcode) {
+ case TS_RPC_ABI_MANAGEMENT_OPCODE_VERSION:
+ ts_rpc_abi_set_version(response, TS_RPC_ABI_VERSION_V1);
+ /* Version call doesn't return RPC status, return from the function here */
+ return;
+
+ case TS_RPC_ABI_MANAGEMENT_OPCODE_MEMORY_RETRIEVE: {
+ uint64_t memory_handle = ts_rpc_abi_get_memory_handle(request);
+ uint64_t memory_tag = ts_rpc_abi_get_memory_tag(request);
+
+ status = handle_memory_retrieve(endpoint, source_id, memory_handle, memory_tag);
+ break;
+ }
+
+ case TS_RPC_ABI_MANAGEMENT_OPCODE_MEMORY_RELINQUISH: {
+ uint64_t memory_handle = ts_rpc_abi_get_memory_handle(request);
+
+ status = handle_memory_relinquish(endpoint, source_id, memory_handle);
+ break;
+ }
+
+ case TS_RPC_ABI_MANAGEMENT_OPCODE_INTERFACE_ID_QUERY: {
+ struct rpc_uuid uuid = { 0 };
+ uint8_t interface_id = 0;
+
+ ts_rpc_abi_get_uuid(request, &uuid);
+ status = handle_interface_id_query(endpoint, &uuid, &interface_id);
+ if (status == RPC_SUCCESS)
+ ts_rpc_abi_set_queried_interface_id(response, interface_id);
+ break;
+ }
+
+ default:
+ status = RPC_ERROR_INVALID_VALUE;
+ }
+
+ ts_rpc_abi_set_rpc_status(response, status);
+}
+
+static void handle_service_interfaces(struct ts_rpc_endpoint_sp *endpoint, uint16_t source_id,
+ const uint32_t request[5], uint32_t response[5])
+{
+ uint8_t interface_id = 0;
+ uint64_t memory_handle = 0;
+ uint32_t request_length = 0;
+ struct rpc_service_interface *service = NULL;
+ const struct ts_rpc_shared_memory *memory = NULL;
+ struct rpc_request rpc_request = { 0 };
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+
+ interface_id = ts_rpc_abi_get_interface_id(request);
+ if (interface_id >= endpoint->service_count) {
+ status = RPC_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ service = endpoint->services[interface_id];
+ if (!service) {
+ status = RPC_ERROR_INTERNAL;
+ goto out;
+ }
+
+ memory_handle = ts_rpc_abi_get_memory_handle(request);
+ if (memory_handle != FFA_MEM_HANDLE_INVALID) {
+ /* Normal call with data in the shared memory */
+ memory = find_shared_memory_descriptor(endpoint, source_id, memory_handle);
+ if (!memory) {
+ status = RPC_ERROR_NOT_FOUND;
+ goto out;
+ }
+ } else {
+ /* Call without a shared memory */
+ memory = &null_shared_memory;
+ }
+
+ request_length = ts_rpc_abi_get_request_length(request);
+ if (request_length > memory->size) {
+ status = RPC_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ rpc_request.request.data = memory->data;
+ rpc_request.request.data_length = request_length;
+ rpc_request.request.size = memory->size;
+
+ rpc_request.response.data = memory->data;
+ rpc_request.response.data_length = 0;
+ rpc_request.response.size = memory->size;
+
+ rpc_request.source_id = source_id;
+ rpc_request.interface_id = interface_id;
+ rpc_request.opcode = ts_rpc_abi_get_opcode(request);
+ rpc_request.client_id = ts_rpc_abi_get_client_id(request);
+
+ status = rpc_service_receive(service, &rpc_request);
+ if (status == RPC_SUCCESS) {
+ ts_rpc_abi_set_response_length(response, rpc_request.response.data_length);
+ ts_rpc_abi_set_service_status(response, rpc_request.service_status);
+ }
+
+out:
+ ts_rpc_abi_set_rpc_status(response, status);
+}
+
+rpc_status_t ts_rpc_endpoint_sp_init(struct ts_rpc_endpoint_sp *endpoint, size_t service_count,
+ size_t shared_memory_count)
+{
+ sp_result result = SP_RESULT_OK;
+
+ if (!endpoint || !service_count)
+ return RPC_ERROR_INVALID_VALUE;
+
+ result = sp_discovery_own_id_get(&endpoint->own_id);
+ if (result != SP_RESULT_OK)
+ return RPC_ERROR_TRANSPORT_LAYER;
+
+ endpoint->services = calloc(service_count, sizeof(struct rpc_service_interface *));
+ if (!endpoint->services)
+ return RPC_ERROR_RESOURCE_FAILURE;
+
+ endpoint->service_count = service_count;
+ endpoint->shared_memories = calloc(shared_memory_count,
+ sizeof(struct ts_rpc_shared_memory));
+ if (!endpoint->shared_memories) {
+ free(endpoint->services);
+ return RPC_ERROR_RESOURCE_FAILURE;
+ }
+
+ endpoint->shared_memory_count = shared_memory_count;
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t ts_rpc_endpoint_sp_deinit(struct ts_rpc_endpoint_sp *endpoint)
+{
+ struct ts_rpc_shared_memory *memory = NULL;
+ struct ts_rpc_shared_memory *end = NULL;
+ rpc_status_t status = RPC_SUCCESS;
+
+ if (!endpoint)
+ return RPC_ERROR_INVALID_VALUE;
+
+ memory = endpoint->shared_memories;
+ end = memory + endpoint->shared_memory_count;
+
+ for (; memory < end; memory++) {
+ status = handle_memory_relinquish(endpoint, memory->owner_id, memory->handle);
+ if (status)
+ return status;
+ }
+
+ free(endpoint->services);
+ free(endpoint->shared_memories);
+
+ *endpoint = (struct ts_rpc_endpoint_sp){ 0 };
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t ts_rpc_endpoint_sp_add_service(struct ts_rpc_endpoint_sp *endpoint,
+ struct rpc_service_interface *service)
+{
+ size_t i = 0;
+
+ if (!endpoint || !service)
+ return RPC_ERROR_INVALID_VALUE;
+
+ for (i = 0; i < endpoint->service_count; i++) {
+ if (!endpoint->services[i]) {
+ endpoint->services[i] = service;
+ return RPC_SUCCESS;
+ }
+ }
+
+ return RPC_ERROR_RESOURCE_FAILURE;
+}
+
+void ts_rpc_endpoint_sp_receive(struct ts_rpc_endpoint_sp *endpoint, const struct sp_msg *request,
+ struct sp_msg *response)
+{
+ response->source_id = request->destination_id;
+ response->destination_id = request->source_id;
+ response->is_64bit_message = request->is_64bit_message;
+ memset(&response->args, 0x00, sizeof(response->args));
+ ts_rpc_abi_copy_control_reg(response->args.args32, request->args.args32);
+
+ if (!request->is_64bit_message) {
+ if (ts_rpc_abi_is_management_interface_id(request->args.args32)) {
+ handle_management_interface(endpoint, request->source_id,
+ request->args.args32, response->args.args32);
+ } else {
+ handle_service_interfaces(endpoint, request->source_id,
+ request->args.args32, response->args.args32);
+ }
+ } else {
+ EMSG("64 bit FF-A messages are not supported by the TS RPC layer, src = 0x%04x",
+ request->source_id);
+ ts_rpc_abi_set_rpc_status(response->args.args32, RPC_ERROR_INVALID_VALUE);
+ }
+}
diff --git a/components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h b/components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h
new file mode 100644
index 000000000..63aa71c31
--- /dev/null
+++ b/components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_RPC_ENDPOINT_SP_H
+#define TS_RPC_ENDPOINT_SP_H
+
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "components/rpc/ts_rpc/common/ts_rpc_abi.h"
+#include "sp_messaging.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief TS RPC shared memory
+ *
+ * The structure describes an FF-A shared memory slot in the endpoint implementation. The shared
+ * memory is identified by its owner (FF-A ID) and handle (FF-A memory handle). After retrieval the
+ * data and size fields are filled. The used field indicates if a given memory slot of the pool is
+ * used and contains valid information.
+ */
+struct ts_rpc_shared_memory {
+ uint16_t owner_id;
+ uint64_t handle;
+ void *data;
+ size_t size;
+ bool used;
+};
+
+/**
+ * @brief TS RPC endpoint for SPs
+ *
+ * This component connects the FF-A layer and the services by implementing TS RPC on FF-A direct
+ * messages and shared memories.
+ * The structure contains the endpoint's own FF-A ID to be used in FF-A calls.
+ * It also contains of list of services. These services are selected based on the interface ID of
+ * the RPC request. The endpoint handles the shared memory pool.
+ */
+struct ts_rpc_endpoint_sp {
+ uint16_t own_id;
+ struct rpc_service_interface **services;
+ size_t service_count;
+ struct ts_rpc_shared_memory *shared_memories;
+ size_t shared_memory_count;
+};
+
+/**
+ * @brief Init TS RPC endpoint
+ *
+ * @param endpoint The endpoint instance
+ * @param service_count Service count
+ * @param shared_memory_count Shared memory pool size
+ * @return rpc_status_t
+ */
+rpc_status_t ts_rpc_endpoint_sp_init(struct ts_rpc_endpoint_sp *endpoint, size_t service_count,
+ size_t shared_memory_count);
+
+/**
+ * @brief Deinit TS RPC endpoint
+ *
+ * @param endpoint The endpoint instance
+ * @return rpc_status_t
+ */
+rpc_status_t ts_rpc_endpoint_sp_deinit(struct ts_rpc_endpoint_sp *endpoint);
+
+/**
+ * @brief Add service to the endpoint. The interface IDs are assigned sequentially. The maximal
+ * service count is determined by the service_count parameter of ts_rpc_endpoint_sp_init.
+ *
+ * @param endpoint The endpoint instance
+ * @param service The service instance
+ * @return rpc_status_t
+ */
+rpc_status_t ts_rpc_endpoint_sp_add_service(struct ts_rpc_endpoint_sp *endpoint,
+ struct rpc_service_interface *service);
+
+/**
+ * @brief Handle received FF-A message
+ *
+ * @param endpoint The endpoint instance
+ * @param request The request FF-A message
+ * @param response The response FF-A message
+ */
+void ts_rpc_endpoint_sp_receive(struct ts_rpc_endpoint_sp *endpoint, const struct sp_msg *request,
+ struct sp_msg *response);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TS_RPC_ENDPOINT_SP_H */
diff --git a/components/service/attestation/claims/sources/event_log/event_log_claim_source.c b/components/service/attestation/claims/sources/event_log/event_log_claim_source.c
index 94b7bb9ec..8ad036223 100644
--- a/components/service/attestation/claims/sources/event_log/event_log_claim_source.c
+++ b/components/service/attestation/claims/sources/event_log/event_log_claim_source.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -263,6 +263,8 @@ static void tcg_event2_extract_digest(const void *header,
static size_t tcg_event1_record_size(const void *header, const void *limit)
{
+ (void)limit;
+
size_t record_len = load_u32_le(header, offsetof(tcg_pcr_event_t, event_size));
record_len += sizeof(tcg_pcr_event_t);
return record_len;
@@ -280,7 +282,7 @@ static void tcg_event2_extract_measurement_id(const void *event_data,
if (id_size) {
- measurement->id.string = (const uint8_t*)event_data + offsetof(event2_data_t, event);
+ measurement->id.string = (const char*)event_data + offsetof(event2_data_t, event);
}
}
}
diff --git a/components/service/attestation/claims/sources/implementation_id/implementation_id_claim_source.c b/components/service/attestation/claims/sources/implementation_id/implementation_id_claim_source.c
index 3610c0728..a76dca36d 100644
--- a/components/service/attestation/claims/sources/implementation_id/implementation_id_claim_source.c
+++ b/components/service/attestation/claims/sources/implementation_id/implementation_id_claim_source.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -33,7 +33,7 @@ static bool get_claim(void *context, struct claim *claim)
claim->variant_id = CLAIM_VARIANT_ID_BYTE_STRING;
claim->raw_data = NULL;
- claim->variant.byte_string.bytes = instance->id_string;
+ claim->variant.byte_string.bytes = (const uint8_t*)instance->id_string;
claim->variant.byte_string.len = strlen(instance->id_string);
}
diff --git a/components/service/attestation/client/provision/attest_provision_client.c b/components/service/attestation/client/provision/attest_provision_client.c
index 5549db1e7..404a54586 100644
--- a/components/service/attestation/client/provision/attest_provision_client.c
+++ b/components/service/attestation/client/provision/attest_provision_client.c
@@ -24,9 +24,9 @@
static struct service_client instance;
-psa_status_t attest_provision_client_init(struct rpc_caller *caller)
+psa_status_t attest_provision_client_init(struct rpc_caller_session *session)
{
- return service_client_init(&instance, caller);
+ return service_client_init(&instance, session);
}
void attest_provision_client_deinit(void)
@@ -51,20 +51,23 @@ psa_status_t attest_provision_export_iak_public_key(
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(instance.caller, &req_buf, 0);
+ call_handle = rpc_caller_session_begin(instance.session, &req_buf, 0,
+ tlv_required_space(data_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
- instance.rpc_status = rpc_caller_invoke(instance.caller, call_handle,
- TS_ATTESTATION_OPCODE_EXPORT_IAK_PUBLIC_KEY, &opstatus, &resp_buf, &resp_len);
+ instance.rpc_status =
+ rpc_caller_session_invoke(call_handle,
+ TS_ATTESTATION_OPCODE_EXPORT_IAK_PUBLIC_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (instance.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -92,7 +95,7 @@ psa_status_t attest_provision_export_iak_public_key(
}
}
- rpc_caller_end(instance.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -113,27 +116,26 @@ psa_status_t attest_provision_import_iak(
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(instance.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(instance.session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
tlv_iterator_begin(&req_iter, req_buf, req_len);
tlv_encode(&req_iter, &key_record);
- instance.rpc_status = rpc_caller_invoke(instance.caller, call_handle,
- TS_ATTESTATION_OPCODE_IMPORT_IAK, &opstatus, &resp_buf, &resp_len);
+ instance.rpc_status =
+ rpc_caller_session_invoke(call_handle, TS_ATTESTATION_OPCODE_IMPORT_IAK,
+ &resp_buf, &resp_len, &service_status);
- if (instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (instance.rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- psa_status = opstatus;
- }
-
- rpc_caller_end(instance.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -146,23 +148,22 @@ psa_status_t attest_provision_iak_exists(void)
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(instance.caller, &req_buf, 0);
+ call_handle = rpc_caller_session_begin(instance.session, &req_buf, 0, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
- instance.rpc_status = rpc_caller_invoke(instance.caller, call_handle,
- TS_ATTESTATION_OPCODE_IAK_EXISTS, &opstatus, &resp_buf, &resp_len);
+ instance.rpc_status =
+ rpc_caller_session_invoke(call_handle, TS_ATTESTATION_OPCODE_IAK_EXISTS,
+ &resp_buf, &resp_len, &service_status);
- if (instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- psa_status = opstatus;
- }
+ if (instance.rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(instance.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/attestation/client/provision/attest_provision_client.h b/components/service/attestation/client/provision/attest_provision_client.h
index 73ddbf72e..300cde706 100644
--- a/components/service/attestation/client/provision/attest_provision_client.h
+++ b/components/service/attestation/client/provision/attest_provision_client.h
@@ -8,7 +8,7 @@
#define ATTEST_PROVISION_CLIENT_H
#include <psa/error.h>
-#include <rpc_caller.h>
+#include "rpc_caller_session.h"
#ifdef __cplusplus
extern "C" {
@@ -23,7 +23,7 @@ extern "C" {
*
* @return A status indicating the success/failure of the operation
*/
-psa_status_t attest_provision_client_init(struct rpc_caller *caller);
+psa_status_t attest_provision_client_init(struct rpc_caller_session *session);
/**
* @brief De-initialises the singleton attestion provisioning client
diff --git a/components/service/attestation/client/psa/iat_client.c b/components/service/attestation/client/psa/iat_client.c
index 07b1cf51c..407572b35 100644
--- a/components/service/attestation/client/psa/iat_client.c
+++ b/components/service/attestation/client/psa/iat_client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <string.h>
#include "iat_client.h"
+#include "rpc_caller_session.h"
#include <common/tlv/tlv.h>
#include <psa/initial_attestation.h>
#include <service/common/client/service_client.h>
@@ -23,9 +24,9 @@
static struct service_client instance;
-psa_status_t psa_iat_client_init(struct rpc_caller *caller)
+psa_status_t psa_iat_client_init(struct rpc_caller_session *session)
{
- return service_client_init(&instance, caller);
+ return service_client_init(&instance, session);
}
void psa_iat_client_deinit(void)
@@ -40,107 +41,109 @@ int psa_iat_client_rpc_status(void)
psa_status_t psa_initial_attest_get_token(
const uint8_t *auth_challenge, size_t challenge_size,
- uint8_t *token_buf, size_t token_buf_size, size_t *token_size)
+ uint8_t *token_buf, size_t token_buf_size, size_t *token_size)
{
- psa_status_t psa_status = PSA_ERROR_INVALID_ARGUMENT;
- size_t req_len = tlv_required_space(challenge_size);
+ psa_status_t psa_status = PSA_ERROR_INVALID_ARGUMENT;
+ size_t req_len = tlv_required_space(challenge_size);
+ struct tlv_record challenge_record = { 0 };
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
- if (!token_buf || !token_buf_size) return PSA_ERROR_INVALID_ARGUMENT;
+ if (!token_buf || !token_buf_size)
+ return PSA_ERROR_INVALID_ARGUMENT;
- struct tlv_record challenge_record;
- challenge_record.tag = TS_ATTESTATION_GET_TOKEN_IN_TAG_AUTH_CHALLENGE;
- challenge_record.length = challenge_size;
- challenge_record.value = auth_challenge;
-
- rpc_call_handle call_handle;
- uint8_t *req_buf;
+ challenge_record.tag = TS_ATTESTATION_GET_TOKEN_IN_TAG_AUTH_CHALLENGE;
+ challenge_record.length = challenge_size;
+ challenge_record.value = auth_challenge;
*token_size = 0;
- call_handle = rpc_caller_begin(instance.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(instance.session, &req_buf, req_len,
+ tlv_required_space(token_buf_size));
- if (call_handle) {
+ if (call_handle) {
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
- struct tlv_iterator req_iter;
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+ struct tlv_iterator req_iter;
- tlv_iterator_begin(&req_iter, req_buf, req_len);
- tlv_encode(&req_iter, &challenge_record);
+ tlv_iterator_begin(&req_iter, req_buf, req_len);
+ tlv_encode(&req_iter, &challenge_record);
- instance.rpc_status = rpc_caller_invoke(instance.caller, call_handle,
- TS_ATTESTATION_OPCODE_GET_TOKEN, &opstatus, &resp_buf, &resp_len);
+ instance.rpc_status =
+ rpc_caller_session_invoke(call_handle, TS_ATTESTATION_OPCODE_GET_TOKEN,
+ &resp_buf, &resp_len, &service_status);
- if (instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (instance.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
+ struct tlv_const_iterator resp_iter;
+ struct tlv_record decoded_record;
- struct tlv_const_iterator resp_iter;
- struct tlv_record decoded_record;
- tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+ tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
- if (tlv_find_decode(&resp_iter,
- TS_ATTESTATION_GET_TOKEN_OUT_TAG_TOKEN, &decoded_record)) {
+ if (tlv_find_decode(&resp_iter,
+ TS_ATTESTATION_GET_TOKEN_OUT_TAG_TOKEN, &decoded_record)) {
- if (decoded_record.length <= token_buf_size) {
+ if (decoded_record.length <= token_buf_size) {
- memcpy(token_buf, decoded_record.value, decoded_record.length);
- *token_size = decoded_record.length;
- }
- else {
- /* Provided buffer is too small */
- psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
- }
- }
- else {
- /* Mandatory response parameter missing */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
+ memcpy(token_buf, decoded_record.value,
+ decoded_record.length);
+ *token_size = decoded_record.length;
+ } else {
+ /* Provided buffer is too small */
+ psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ } else {
+ /* Mandatory response parameter missing */
+ psa_status = PSA_ERROR_GENERIC_ERROR;
+ }
}
- }
+ }
- rpc_caller_end(instance.caller, call_handle);
- }
+ rpc_caller_session_end(call_handle);
+ }
- return psa_status;
+ return psa_status;
}
psa_status_t psa_initial_attest_get_token_size(
size_t challenge_size, size_t *token_size)
{
- psa_status_t psa_status = PSA_ERROR_INVALID_ARGUMENT;
- struct ts_attestation_get_token_size_in req_msg;
- size_t req_len = sizeof(struct ts_attestation_get_token_size_in);
+ psa_status_t psa_status = PSA_ERROR_INVALID_ARGUMENT;
+ struct ts_attestation_get_token_size_in req_msg;
+ size_t req_len = sizeof(struct ts_attestation_get_token_size_in);
- *token_size = 0; /* For failure case */
+ *token_size = 0; /* For failure case */
- req_msg.challenge_size = challenge_size;
+ req_msg.challenge_size = challenge_size;
- rpc_call_handle call_handle;
- uint8_t *req_buf;
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
- call_handle = rpc_caller_begin(instance.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(instance.session, &req_buf, req_len,
+ sizeof(struct ts_attestation_get_token_size_out));
- if (call_handle) {
+ if (call_handle) {
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
- struct tlv_iterator req_iter;
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
- memcpy(req_buf, &req_msg, req_len);
+ memcpy(req_buf, &req_msg, req_len);
- instance.rpc_status = rpc_caller_invoke(instance.caller, call_handle,
- TS_ATTESTATION_OPCODE_GET_TOKEN_SIZE, &opstatus, &resp_buf, &resp_len);
+ instance.rpc_status =
+ rpc_caller_session_invoke(call_handle, TS_ATTESTATION_OPCODE_GET_TOKEN_SIZE,
+ &resp_buf, &resp_len, &service_status);
- if (instance.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (instance.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
- if (psa_status == PSA_SUCCESS) {
+ if (psa_status == PSA_SUCCESS) {
if (resp_len >= sizeof(struct ts_attestation_get_token_size_out)) {
@@ -152,11 +155,11 @@ psa_status_t psa_initial_attest_get_token_size(
/* Failed to decode response message */
psa_status = PSA_ERROR_GENERIC_ERROR;
}
- }
- }
+ }
+ }
- rpc_caller_end(instance.caller, call_handle);
- }
+ rpc_caller_session_end(call_handle);
+ }
- return psa_status;
+ return psa_status;
}
diff --git a/components/service/attestation/client/psa/iat_client.h b/components/service/attestation/client/psa/iat_client.h
index 7daeacf29..d4ee4f865 100644
--- a/components/service/attestation/client/psa/iat_client.h
+++ b/components/service/attestation/client/psa/iat_client.h
@@ -8,7 +8,7 @@
#define PSA_IAT_CLIENT_H
#include <psa/error.h>
-#include <rpc_caller.h>
+#include "rpc_caller_session.h"
#ifdef __cplusplus
extern "C" {
@@ -25,7 +25,7 @@ extern "C" {
*
* @return A status indicating the success/failure of the operation
*/
-psa_status_t psa_iat_client_init(struct rpc_caller *caller);
+psa_status_t psa_iat_client_init(struct rpc_caller_session *session);
/**
* @brief De-initialises the singleton IAT client
diff --git a/components/service/attestation/client/psa_ipc/component.cmake b/components/service/attestation/client/psa_ipc/component.cmake
new file mode 100644
index 000000000..ec581de3f
--- /dev/null
+++ b/components/service/attestation/client/psa_ipc/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/iat_ipc_client.c"
+ )
diff --git a/components/service/attestation/client/psa_ipc/iat_ipc_client.c b/components/service/attestation/client/psa_ipc/iat_ipc_client.c
new file mode 100644
index 000000000..142073160
--- /dev/null
+++ b/components/service/attestation/client/psa_ipc/iat_ipc_client.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "../psa/iat_client.h"
+#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/initial_attestation.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+
+/**
+ * @brief The singleton psa_iat_client instance
+ *
+ * The psa attestation C API assumes a single backend service provider.
+ */
+static struct service_client instance;
+
+
+psa_status_t psa_iat_client_init(struct rpc_caller_session *session)
+{
+ return service_client_init(&instance, session);
+}
+
+void psa_iat_client_deinit(void)
+{
+ service_client_deinit(&instance);
+}
+
+int psa_iat_client_rpc_status(void)
+{
+ return instance.rpc_status;
+}
+
+psa_status_t psa_initial_attest_get_token(const uint8_t *auth_challenge,
+ size_t challenge_size,
+ uint8_t *token_buf,
+ size_t token_buf_size,
+ size_t *token_size)
+{
+ psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+ struct rpc_caller_interface *caller = instance.session->caller;
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_const_to_u32(auth_challenge), .len = challenge_size},
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(token_buf), .len = token_buf_size},
+ };
+
+ if (!token_buf || !token_buf_size)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ status = psa_call(caller, TFM_ATTESTATION_SERVICE_HANDLE,
+ TFM_ATTEST_GET_TOKEN, in_vec, IOVEC_LEN(in_vec),
+ out_vec, IOVEC_LEN(out_vec));
+ if (status == PSA_SUCCESS) {
+ *token_size = out_vec[0].len;
+ }
+
+ return status;
+}
+
+psa_status_t psa_initial_attest_get_token_size(size_t challenge_size,
+ size_t *token_size)
+{
+ struct rpc_caller_interface *caller = instance.session->caller;
+ psa_status_t status;
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&challenge_size), .len = sizeof(uint32_t)}
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(token_size), .len = sizeof(uint32_t)}
+ };
+
+ status = psa_call(caller, TFM_ATTESTATION_SERVICE_HANDLE,
+ TFM_ATTEST_GET_TOKEN_SIZE,
+ in_vec, IOVEC_LEN(in_vec),
+ out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
diff --git a/components/service/attestation/key_mngr/stub/stub_attest_key_mngr.c b/components/service/attestation/key_mngr/stub/stub_attest_key_mngr.c
index 7f86861c7..2100ee584 100644
--- a/components/service/attestation/key_mngr/stub/stub_attest_key_mngr.c
+++ b/components/service/attestation/key_mngr/stub/stub_attest_key_mngr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,12 +10,18 @@
psa_status_t attest_key_mngr_get_iak_id(
psa_key_id_t *iak_id)
{
+ (void)iak_id;
+
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t attest_key_mngr_export_iak_public_key(
uint8_t *data, size_t data_size, size_t *data_length)
{
+ (void)data;
+ (void)data_size;
+ (void)data_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -32,6 +38,9 @@ size_t attest_key_mngr_max_iak_import_size(void)
psa_status_t attest_key_mngr_import_iak(
const uint8_t *data, size_t data_length)
{
+ (void)data;
+ (void)data_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/attestation/provider/attest_provider.c b/components/service/attestation/provider/attest_provider.c
index c11f8ec5c..dd1f3e532 100644
--- a/components/service/attestation/provider/attest_provider.c
+++ b/components/service/attestation/provider/attest_provider.c
@@ -1,231 +1,193 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+
+#include "attest_provider.h"
+#include "protocols/service/attestation/packed-c/opcodes.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "service/attestation/key_mngr/attest_key_mngr.h"
+#include "service/attestation/reporter/attest_report.h"
+#include "psa/initial_attestation.h"
+#include "attestation_uuid.h"
#include <stdlib.h>
#include <string.h>
-#include <protocols/service/attestation/packed-c/opcodes.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <service/attestation/key_mngr/attest_key_mngr.h>
-#include <service/attestation/reporter/attest_report.h>
-#include <psa/initial_attestation.h>
-#include "attest_provider.h"
/* Service request handlers */
-static rpc_status_t get_token_handler(void *context, struct call_req* req);
-static rpc_status_t get_token_size_handler(void *context, struct call_req* req);
-static rpc_status_t export_iak_public_key_handler(void *context, struct call_req* req);
-static rpc_status_t import_iak_handler(void *context, struct call_req* req);
-static rpc_status_t iak_exists_handler(void *context, struct call_req* req);
+static rpc_status_t get_token_handler(void *context, struct rpc_request *req);
+static rpc_status_t get_token_size_handler(void *context, struct rpc_request *req);
+static rpc_status_t export_iak_public_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t import_iak_handler(void *context, struct rpc_request *req);
+static rpc_status_t iak_exists_handler(void *context, struct rpc_request *req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
- {TS_ATTESTATION_OPCODE_GET_TOKEN, get_token_handler},
- {TS_ATTESTATION_OPCODE_GET_TOKEN_SIZE, get_token_size_handler},
- {TS_ATTESTATION_OPCODE_EXPORT_IAK_PUBLIC_KEY, export_iak_public_key_handler},
- {TS_ATTESTATION_OPCODE_IMPORT_IAK, import_iak_handler},
- {TS_ATTESTATION_OPCODE_IAK_EXISTS, iak_exists_handler}
+ {TS_ATTESTATION_OPCODE_GET_TOKEN, get_token_handler},
+ {TS_ATTESTATION_OPCODE_GET_TOKEN_SIZE, get_token_size_handler},
+ {TS_ATTESTATION_OPCODE_EXPORT_IAK_PUBLIC_KEY, export_iak_public_key_handler},
+ {TS_ATTESTATION_OPCODE_IMPORT_IAK, import_iak_handler},
+ {TS_ATTESTATION_OPCODE_IAK_EXISTS, iak_exists_handler}
};
-struct rpc_interface *attest_provider_init(struct attest_provider *context)
+struct rpc_service_interface *attest_provider_init(struct attest_provider *context)
{
- struct rpc_interface *rpc_interface = NULL;
+ const struct rpc_uuid attest_service_uuid = { .uuid = TS_PSA_ATTESTATION_SERVICE_UUID };
- if (context) {
+ if (!context)
+ return NULL;
- for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
- context->serializers[encoding] = NULL;
+ context->serializer = NULL;
- service_provider_init(&context->base_provider, context,
- handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+ service_provider_init(&context->base_provider, context, &attest_service_uuid,
+ handler_table, sizeof(handler_table)/sizeof(struct service_handler));
- rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
- }
-
- return rpc_interface;
+ return service_provider_get_rpc_interface(&context->base_provider);
}
void attest_provider_deinit(struct attest_provider *context)
{
- (void)context;
+ (void)context;
}
void attest_provider_register_serializer(struct attest_provider *context,
- unsigned int encoding, const struct attest_provider_serializer *serializer)
+ const struct attest_provider_serializer *serializer)
{
- if (encoding < TS_RPC_ENCODING_LIMIT)
- context->serializers[encoding] = serializer;
+ context->serializer = serializer;
}
-static const struct attest_provider_serializer *get_attest_serializer(
- struct attest_provider *context, const struct call_req *req)
+static rpc_status_t get_token_handler(void *context, struct rpc_request *req)
{
- const struct attest_provider_serializer *serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
-
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = context->serializers[encoding];
-
- return serializer;
-}
-
-static rpc_status_t get_token_handler(void *context, struct call_req* req)
-{
- struct attest_provider *this_instance = (struct attest_provider*)context;
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-
- uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
- size_t challenge_len = sizeof(challenge);
-
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct attest_provider_serializer *serializer = get_attest_serializer(this_instance, req);
+ struct attest_provider *this_instance = (struct attest_provider *)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
+ size_t challenge_len = sizeof(challenge);
+ const struct attest_provider_serializer *serializer = this_instance->serializer;
+ const uint8_t *token = NULL;
+ size_t token_size = 0;
- if (serializer)
- rpc_status = serializer->deserialize_get_token_req(req_buf, challenge, &challenge_len);
+ if (!serializer)
+ return rpc_status;
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ rpc_status = serializer->deserialize_get_token_req(&req->request, challenge,
+ &challenge_len);
+ if (rpc_status != RPC_SUCCESS)
+ return rpc_status;
- const uint8_t *token = NULL;
- size_t token_size = 0;
+ req->service_status = attest_report_create((int32_t)req->source_id, challenge,
+ challenge_len, &token, &token_size);
- rpc_opstatus_t opstatus = attest_report_create((int32_t)call_req_get_caller_id(req),
- challenge, challenge_len,
- &token, &token_size);
+ if (req->service_status == PSA_SUCCESS)
+ rpc_status = serializer->serialize_get_token_resp(&req->response, token,
+ token_size);
- if (opstatus == PSA_SUCCESS) {
+ attest_report_destroy(token);
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_get_token_resp(resp_buf, token, token_size);
- }
-
- attest_report_destroy(token);
- call_req_set_opstatus(req, opstatus);
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t get_token_size_handler(void *context, struct call_req* req)
+static rpc_status_t get_token_size_handler(void *context, struct rpc_request *req)
{
- struct attest_provider *this_instance = (struct attest_provider*)context;
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-
- uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
- size_t challenge_len = sizeof(challenge);
-
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct attest_provider_serializer *serializer = get_attest_serializer(this_instance, req);
-
- memset(challenge, 0, sizeof(challenge));
+ struct attest_provider *this_instance = (struct attest_provider*)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
+ size_t challenge_len = sizeof(challenge);
+ const struct attest_provider_serializer *serializer = this_instance->serializer;
+ const uint8_t *token = NULL;
+ size_t token_size = 0;
- if (serializer)
- rpc_status = serializer->deserialize_get_token_size_req(req_buf, &challenge_len);
+ memset(challenge, 0, sizeof(challenge));
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (!serializer)
+ return rpc_status;
- const uint8_t *token = NULL;
- size_t token_size = 0;
+ rpc_status = serializer->deserialize_get_token_size_req(&req->request, &challenge_len);
+ if (rpc_status != RPC_SUCCESS)
+ return rpc_status;
- rpc_opstatus_t opstatus = attest_report_create((int32_t)call_req_get_caller_id(req),
- challenge, challenge_len,
- &token, &token_size);
+ req->service_status = attest_report_create((int32_t)req->source_id, challenge,
+ challenge_len, &token, &token_size);
- if (opstatus == PSA_SUCCESS) {
+ if (req->service_status == PSA_SUCCESS)
+ rpc_status = serializer->serialize_get_token_size_resp(&req->response, token_size);
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_get_token_size_resp(resp_buf, token_size);
- }
+ attest_report_destroy(token);
- attest_report_destroy(token);
- call_req_set_opstatus(req, opstatus);
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t export_iak_public_key_handler(void *context, struct call_req* req)
+static rpc_status_t export_iak_public_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct attest_provider_serializer *serializer = get_attest_serializer(context, req);
-
- if (serializer) {
+ struct attest_provider *this_instance = (struct attest_provider *)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ const struct attest_provider_serializer *serializer = this_instance->serializer;
+ size_t max_key_size = 0;
+ uint8_t *key_buffer = NULL;
+ size_t export_size = 0;
- size_t max_key_size = attest_key_mngr_max_iak_export_size();
+ if (!serializer)
+ return rpc_status;
- uint8_t *key_buffer = malloc(max_key_size);
+ max_key_size = attest_key_mngr_max_iak_export_size();
+ key_buffer = malloc(max_key_size);
- if (key_buffer) {
+ if (!key_buffer)
+ return rpc_status;
- rpc_opstatus_t opstatus;
- size_t export_size;
- opstatus =
- attest_key_mngr_export_iak_public_key(key_buffer, max_key_size, &export_size);
+ req->service_status = attest_key_mngr_export_iak_public_key(key_buffer, max_key_size,
+ &export_size);
- if (opstatus == PSA_SUCCESS) {
+ rpc_status = RPC_SUCCESS;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status =
- serializer->serialize_export_iak_public_key_resp(resp_buf,
- key_buffer, export_size);
- }
+ if (req->service_status == PSA_SUCCESS)
+ rpc_status = serializer->serialize_export_iak_public_key_resp(
+ &req->response, key_buffer, export_size);
- free(key_buffer);
- call_req_set_opstatus(req, opstatus);
- }
- else {
- /* Failed to allocate key buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
- }
+ free(key_buffer);
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t import_iak_handler(void *context, struct call_req* req)
+static rpc_status_t import_iak_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct attest_provider_serializer *serializer = get_attest_serializer(context, req);
-
- if (serializer) {
+ struct attest_provider *this_instance = (struct attest_provider *)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ const struct attest_provider_serializer *serializer = this_instance->serializer;
+ size_t key_data_len = 0;
+ uint8_t *key_buffer = NULL;
- size_t key_data_len = attest_key_mngr_max_iak_import_size();
- uint8_t *key_buffer = malloc(key_data_len);
+ if (!serializer)
+ return rpc_status;
- if (key_buffer) {
+ key_data_len = attest_key_mngr_max_iak_import_size();
+ key_buffer = malloc(key_data_len);
- rpc_status =
- serializer->deserialize_import_iak_req(req_buf, key_buffer, &key_data_len);
+ if (!key_buffer)
+ return rpc_status;
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ rpc_status = serializer->deserialize_import_iak_req(&req->request, key_buffer,
+ &key_data_len);
- rpc_opstatus_t opstatus;
- opstatus = attest_key_mngr_import_iak(key_buffer, key_data_len);
- call_req_set_opstatus(req, opstatus);
- }
+ if (rpc_status == RPC_SUCCESS)
+ req->service_status = attest_key_mngr_import_iak(key_buffer, key_data_len);
- free(key_buffer);
- }
- else {
+ free(key_buffer);
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t iak_exists_handler(void *context, struct call_req* req)
+static rpc_status_t iak_exists_handler(void *context, struct rpc_request *req)
{
- rpc_opstatus_t opstatus = PSA_ERROR_DOES_NOT_EXIST;
+ (void)context;
+
+ service_status_t opstatus = PSA_ERROR_DOES_NOT_EXIST;
- if (attest_key_mngr_iak_exists()) {
+ if (attest_key_mngr_iak_exists()) {
- opstatus = PSA_SUCCESS;
- }
+ opstatus = PSA_SUCCESS;
+ }
- call_req_set_opstatus(req, opstatus);
+ req->service_status = opstatus;
- return TS_RPC_CALL_ACCEPTED;
+ return RPC_SUCCESS;
}
diff --git a/components/service/attestation/provider/attest_provider.h b/components/service/attestation/provider/attest_provider.h
index 26f21b591..4f2e26844 100644
--- a/components/service/attestation/provider/attest_provider.h
+++ b/components/service/attestation/provider/attest_provider.h
@@ -7,12 +7,12 @@
#ifndef ATTEST_PROVIDER_H
#define ATTEST_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
-#include <rpc_caller.h>
-#include <service/common/provider/service_provider.h>
-#include <service/attestation/provider/serializer/attest_provider_serializer.h>
-#include <service/attestation/key_mngr/attest_key_mngr.h>
-#include <protocols/rpc/common/packed-c/encoding.h>
+#include "rpc/common/endpoint/rpc_service_interface.h"
+#include "rpc/common/caller/rpc_caller.h"
+#include "service/common/provider/service_provider.h"
+#include "service/attestation/provider/serializer/attest_provider_serializer.h"
+#include "service/attestation/key_mngr/attest_key_mngr.h"
+#include "protocols/rpc/common/packed-c/encoding.h"
#ifdef __cplusplus
extern "C" {
@@ -24,8 +24,8 @@ extern "C" {
*/
struct attest_provider
{
- struct service_provider base_provider;
- const struct attest_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
+ struct service_provider base_provider;
+ const struct attest_provider_serializer *serializer;
};
/**
@@ -38,7 +38,7 @@ struct attest_provider
*
* \return An rpc_interface or NULL on failure
*/
-struct rpc_interface *attest_provider_init(struct attest_provider *context);
+struct rpc_service_interface *attest_provider_init(struct attest_provider *context);
/**
* \brief Cleans up when the instance is no longer needed
@@ -55,7 +55,7 @@ void attest_provider_deinit(struct attest_provider *context);
* \param[in] serializer A concrete serializer
*/
void attest_provider_register_serializer(struct attest_provider *context,
- unsigned int encoding, const struct attest_provider_serializer *serializer);
+ const struct attest_provider_serializer *serializer);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/components/service/attestation/provider/attestation_uuid.h b/components/service/attestation/provider/attestation_uuid.h
new file mode 100644
index 000000000..4c08760d5
--- /dev/null
+++ b/components/service/attestation/provider/attestation_uuid.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ATTESTATION_UUID_H
+#define ATTESTATION_UUID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TS_PSA_ATTESTATION_SERVICE_UUID \
+{ 0xa1, 0xba, 0xf1, 0x55, 0x88, 0x76, 0x46, 0x95, 0x8f, 0x7c, 0x54, 0x95, 0x5e, 0x8d, 0xb9, 0x74 }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ATTESTATION_UUID_H */
diff --git a/components/service/attestation/provider/serializer/attest_provider_serializer.h b/components/service/attestation/provider/serializer/attest_provider_serializer.h
index 1c05ab07e..78b11a66f 100644
--- a/components/service/attestation/provider/serializer/attest_provider_serializer.h
+++ b/components/service/attestation/provider/serializer/attest_provider_serializer.h
@@ -7,9 +7,9 @@
#ifndef ATTEST_PROVIDER_SERIALIZER_H
#define ATTEST_PROVIDER_SERIALIZER_H
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include <stddef.h>
#include <stdint.h>
-#include <rpc/common/endpoint/rpc_interface.h>
/* Provides a common interface for parameter serialization operations
* for the attestation service provider. Allows alternative serialization
@@ -19,28 +19,28 @@
*/
struct attest_provider_serializer {
- /* Operation: get_token */
- rpc_status_t (*deserialize_get_token_req)(const struct call_param_buf *req_buf,
- uint8_t *auth_challenge, size_t *auth_challenge_len);
+ /* Operation: get_token */
+ rpc_status_t (*deserialize_get_token_req)(const struct rpc_buffer *req_buf,
+ uint8_t *auth_challenge,
+ size_t *auth_challenge_len);
- rpc_status_t (*serialize_get_token_resp)(struct call_param_buf *resp_buf,
- const uint8_t *token,
- size_t token_size);
+ rpc_status_t (*serialize_get_token_resp)(struct rpc_buffer *resp_buf, const uint8_t *token,
+ size_t token_size);
- /* Operation: get_token_size */
- rpc_status_t (*deserialize_get_token_size_req)(const struct call_param_buf *req_buf,
- size_t *auth_challenge_len);
+ /* Operation: get_token_size */
+ rpc_status_t (*deserialize_get_token_size_req)(const struct rpc_buffer *req_buf,
+ size_t *auth_challenge_len);
- rpc_status_t (*serialize_get_token_size_resp)(struct call_param_buf *resp_buf,
- size_t token_size);
+ rpc_status_t (*serialize_get_token_size_resp)(struct rpc_buffer *resp_buf,
+ size_t token_size);
- /* Operation: export_iak_public_key */
- rpc_status_t (*serialize_export_iak_public_key_resp)(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len);
+ /* Operation: export_iak_public_key */
+ rpc_status_t (*serialize_export_iak_public_key_resp)(struct rpc_buffer *resp_buf,
+ const uint8_t *data, size_t data_len);
- /* Operation: import_iak */
- rpc_status_t (*deserialize_import_iak_req)(const struct call_param_buf *req_buf,
- uint8_t *data, size_t *data_len);
+ /* Operation: import_iak */
+ rpc_status_t (*deserialize_import_iak_req)(const struct rpc_buffer *req_buf, uint8_t *data,
+ size_t *data_len);
};
#endif /* ATTEST_PROVIDER_SERIALIZER_H */
diff --git a/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.c b/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.c
index 65e76f304..e2c6ea150 100644
--- a/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.c
+++ b/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.c
@@ -3,159 +3,158 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <string.h>
+
#include <common/tlv/tlv.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <protocols/service/attestation/packed-c/get_token.h>
-#include <protocols/service/attestation/packed-c/get_token_size.h>
-#include <protocols/service/attestation/packed-c/export_iak_public_key.h>
-#include <protocols/service/attestation/packed-c/import_iak.h>
#include "packedc_attest_provider_serializer.h"
-
+#include "protocols/rpc/common/packed-c/status.h"
+#include "protocols/service/attestation/packed-c/get_token.h"
+#include "protocols/service/attestation/packed-c/get_token_size.h"
+#include "protocols/service/attestation/packed-c/export_iak_public_key.h"
+#include "protocols/service/attestation/packed-c/import_iak.h"
+#include <string.h>
/* Operation: get_token */
-static rpc_status_t deserialize_get_token_req(const struct call_param_buf *req_buf,
- uint8_t *auth_challenge, size_t *auth_challenge_len)
+static rpc_status_t deserialize_get_token_req(const struct rpc_buffer *req_buf,
+ uint8_t *auth_challenge, size_t *auth_challenge_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct tlv_const_iterator req_iter;
- struct tlv_record decoded_record;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct tlv_const_iterator req_iter = { 0 };
+ struct tlv_record decoded_record = { 0 };
- tlv_const_iterator_begin(&req_iter, (uint8_t*)req_buf->data, req_buf->data_len);
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data, req_buf->data_length);
- if (tlv_find_decode(&req_iter,
- TS_ATTESTATION_GET_TOKEN_IN_TAG_AUTH_CHALLENGE, &decoded_record)) {
+ if (tlv_find_decode(&req_iter,
+ TS_ATTESTATION_GET_TOKEN_IN_TAG_AUTH_CHALLENGE, &decoded_record)) {
- if (decoded_record.length <= *auth_challenge_len) {
+ if (decoded_record.length <= *auth_challenge_len) {
- memcpy(auth_challenge, decoded_record.value, decoded_record.length);
- *auth_challenge_len = decoded_record.length;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
+ memcpy(auth_challenge, decoded_record.value, decoded_record.length);
+ *auth_challenge_len = decoded_record.length;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_get_token_resp(struct call_param_buf *resp_buf,
- const uint8_t *token, size_t token_size)
+static rpc_status_t serialize_get_token_resp(struct rpc_buffer *resp_buf, const uint8_t *token,
+ size_t token_size)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct tlv_iterator resp_iter;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter = { 0 };
+ struct tlv_record token_record = { 0 };
- struct tlv_record token_record;
- token_record.tag = TS_ATTESTATION_GET_TOKEN_OUT_TAG_TOKEN;
- token_record.length = token_size;
- token_record.value = token;
+ token_record.tag = TS_ATTESTATION_GET_TOKEN_OUT_TAG_TOKEN;
+ token_record.length = token_size;
+ token_record.value = token;
- tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
- if (tlv_encode(&resp_iter, &token_record)) {
+ if (tlv_encode(&resp_iter, &token_record)) {
- resp_buf->data_len = tlv_required_space(token_size);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ resp_buf->data_length = tlv_required_space(token_size);
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: get_token_size */
-static rpc_status_t deserialize_get_token_size_req(const struct call_param_buf *req_buf,
- size_t *auth_challenge_len)
+static rpc_status_t deserialize_get_token_size_req(const struct rpc_buffer *req_buf,
+ size_t *auth_challenge_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_attestation_get_token_size_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_attestation_get_token_size_in);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_attestation_get_token_size_in recv_msg = { 0 };
+ size_t expected_fixed_len = sizeof(struct ts_attestation_get_token_size_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- *auth_challenge_len = recv_msg.challenge_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *auth_challenge_len = recv_msg.challenge_size;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_get_token_size_resp(struct call_param_buf *resp_buf,
- size_t token_size)
+static rpc_status_t serialize_get_token_size_resp(struct rpc_buffer *resp_buf, size_t token_size)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct ts_attestation_get_token_size_out resp_msg;
- size_t fixed_len = sizeof(struct ts_attestation_get_token_size_out);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_attestation_get_token_size_out resp_msg = { 0 };
+ size_t fixed_len = sizeof(struct ts_attestation_get_token_size_out);
- resp_msg.token_size = token_size;
+ resp_msg.token_size = token_size;
- if (fixed_len <= resp_buf->size) {
+ if (fixed_len <= resp_buf->size) {
- memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: export_iak_public_key */
-static rpc_status_t serialize_export_iak_public_key_resp(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len)
+static rpc_status_t serialize_export_iak_public_key_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *data, size_t data_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct tlv_iterator resp_iter;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter = { 0 };
+ struct tlv_record key_record = { 0 };
- struct tlv_record key_record;
- key_record.tag = TS_ATTESTATION_EXPORT_IAK_PUBLIC_KEY_OUT_TAG_DATA;
- key_record.length = data_len;
- key_record.value = data;
+ key_record.tag = TS_ATTESTATION_EXPORT_IAK_PUBLIC_KEY_OUT_TAG_DATA;
+ key_record.length = data_len;
+ key_record.value = data;
- tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
- if (tlv_encode(&resp_iter, &key_record)) {
+ if (tlv_encode(&resp_iter, &key_record)) {
- resp_buf->data_len = tlv_required_space(data_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ resp_buf->data_length = tlv_required_space(data_len);
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: import_iak */
-static rpc_status_t deserialize_import_iak_req(const struct call_param_buf *req_buf,
- uint8_t *data, size_t *data_len)
+static rpc_status_t deserialize_import_iak_req(const struct rpc_buffer *req_buf, uint8_t *data,
+ size_t *data_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct tlv_const_iterator req_iter;
- struct tlv_record decoded_record;
- size_t out_buf_size = *data_len;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct tlv_const_iterator req_iter = { 0 };
+ struct tlv_record decoded_record = { 0 };
+ size_t out_buf_size = *data_len;
- *data_len = 0;
+ *data_len = 0;
- tlv_const_iterator_begin(&req_iter, (uint8_t*)req_buf->data, req_buf->data_len);
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data, req_buf->data_length);
- if (tlv_find_decode(&req_iter, TS_ATTESTATION_IMPORT_IAK_IN_TAG_DATA, &decoded_record)) {
+ if (tlv_find_decode(&req_iter, TS_ATTESTATION_IMPORT_IAK_IN_TAG_DATA, &decoded_record)) {
- if (decoded_record.length <= out_buf_size) {
+ if (decoded_record.length <= out_buf_size) {
- memcpy(data, decoded_record.value, decoded_record.length);
- *data_len = decoded_record.length;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
+ memcpy(data, decoded_record.value, decoded_record.length);
+ *data_len = decoded_record.length;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
- return rpc_status;
+ return rpc_status;
}
/* Singleton method to provide access to the serializer instance */
const struct attest_provider_serializer *packedc_attest_provider_serializer_instance(void)
{
- static const struct attest_provider_serializer instance = {
- deserialize_get_token_req,
- serialize_get_token_resp,
- deserialize_get_token_size_req,
- serialize_get_token_size_resp,
- serialize_export_iak_public_key_resp,
- deserialize_import_iak_req
- };
-
- return &instance;
+ static const struct attest_provider_serializer instance = {
+ deserialize_get_token_req,
+ serialize_get_token_resp,
+ deserialize_get_token_size_req,
+ serialize_get_token_size_resp,
+ serialize_export_iak_public_key_resp,
+ deserialize_import_iak_req
+ };
+
+ return &instance;
}
diff --git a/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h b/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h
index b73adf8de..436767b85 100644
--- a/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h
+++ b/components/service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h
@@ -7,7 +7,7 @@
#ifndef PACKEDC_ATTEST_PROVIDER_SERIALIZER_H
#define PACKEDC_ATTEST_PROVIDER_SERIALIZER_H
-#include <service/attestation/provider/serializer/attest_provider_serializer.h>
+#include "components/service/attestation/provider/serializer/attest_provider_serializer.h"
#ifdef __cplusplus
extern "C" {
diff --git a/components/service/attestation/reporter/eat/eat_serializer.c b/components/service/attestation/reporter/eat/eat_serializer.c
index 240c674c6..e948218fc 100644
--- a/components/service/attestation/reporter/eat/eat_serializer.c
+++ b/components/service/attestation/reporter/eat/eat_serializer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -78,6 +78,8 @@ static bool alloc_encode_buffer(const struct claim_vector *device_claims,
const struct claim_vector *sw_claims, UsefulBuf *encode_buffer)
{
// todo estimate required space
+ (void)device_claims;
+ (void)sw_claims;
encode_buffer->len = 4096;
encode_buffer->ptr = malloc(encode_buffer->len);
diff --git a/components/service/attestation/reporter/psa_ipc/component.cmake b/components/service/attestation/reporter/psa_ipc/component.cmake
new file mode 100644
index 000000000..e3dd0b79f
--- /dev/null
+++ b/components/service/attestation/reporter/psa_ipc/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/psa_ipc_attest_report.c"
+ )
diff --git a/components/service/attestation/reporter/psa_ipc/psa_ipc_attest_report.c b/components/service/attestation/reporter/psa_ipc/psa_ipc_attest_report.c
new file mode 100644
index 000000000..c0bda914e
--- /dev/null
+++ b/components/service/attestation/reporter/psa_ipc/psa_ipc_attest_report.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * A attestation reporter for psa ipc
+ */
+
+#include <stddef.h>
+#include <psa/error.h>
+#include <service/attestation/reporter/attest_report.h>
+#include <psa/initial_attestation.h>
+
+#define TOKEN_BUF_SIZE 1024
+
+static uint8_t token_buf[TOKEN_BUF_SIZE];
+
+int attest_report_create(int32_t client_id, const uint8_t *auth_challenge_data,
+ size_t auth_challenge_len, const uint8_t **report,
+ size_t *report_len)
+{
+ *report = token_buf;
+ psa_status_t ret;
+ size_t token_size = 0;
+
+ ret = psa_initial_attest_get_token(auth_challenge_data,
+ auth_challenge_len, token_buf,
+ TOKEN_BUF_SIZE, &token_size);
+ if (ret != PSA_SUCCESS) {
+ *report = NULL;
+ *report_len = 0;
+ return ret;
+ }
+
+ *report_len = token_size;
+
+ return PSA_SUCCESS;
+}
+
+void attest_report_destroy(const uint8_t *report)
+{
+ (void)report;
+}
diff --git a/components/service/attestation/reporter/stub/stub_attest_report.c b/components/service/attestation/reporter/stub/stub_attest_report.c
index d24dd5ecc..b6589ff7f 100644
--- a/components/service/attestation/reporter/stub/stub_attest_report.c
+++ b/components/service/attestation/reporter/stub/stub_attest_report.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,6 +19,10 @@ int attest_report_create(int32_t client_id,
const uint8_t *auth_challenge_data, size_t auth_challenge_len,
const uint8_t **report, size_t *report_len)
{
+ (void)client_id;
+ (void)auth_challenge_data;
+ (void)auth_challenge_len;
+
*report = NULL;
*report_len = 0;
diff --git a/components/service/attestation/test/component/attestation_reporter_tests.cpp b/components/service/attestation/test/component/attestation_reporter_tests.cpp
index ed5ac14ab..59386eae6 100644
--- a/components/service/attestation/test/component/attestation_reporter_tests.cpp
+++ b/components/service/attestation/test/component/attestation_reporter_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -30,7 +30,7 @@ TEST_GROUP(AttestationReporterTests)
struct claim_source *claim_source;
report = NULL;
- report_len;
+ report_len = 0;
psa_crypto_init();
local_attest_key_mngr_init(LOCAL_ATTEST_KEY_MNGR_VOLATILE_IAK);
diff --git a/components/service/attestation/test/service/attestation_provisioning_tests.cpp b/components/service/attestation/test/service/attestation_provisioning_tests.cpp
index 4237bdf87..1a15b3d3e 100644
--- a/components/service/attestation/test/service/attestation_provisioning_tests.cpp
+++ b/components/service/attestation/test/service/attestation_provisioning_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,37 +19,38 @@ TEST_GROUP(AttestationProvisioningTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_attest_service_context = NULL;
service_locator_init();
m_attest_service_context =
- service_locator_query("sn:trustedfirmware.org:attestation:0", &status);
+ service_locator_query("sn:trustedfirmware.org:attestation:0");
CHECK_TRUE(m_attest_service_context);
- m_rpc_session_handle =
- service_context_open(m_attest_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session =
+ service_context_open(m_attest_service_context);
+ CHECK_TRUE(m_rpc_session);
- attest_provision_client_init(caller);
+ attest_provision_client_init(m_rpc_session);
}
void teardown()
{
attest_provision_client_deinit();
- service_context_close(m_attest_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_attest_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_attest_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_attest_service_context);
- m_attest_service_context = NULL;
+ service_context_relinquish(m_attest_service_context);
+ m_attest_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_attest_service_context;
};
diff --git a/components/service/attestation/test/service/attestation_service_tests.cpp b/components/service/attestation/test/service/attestation_service_tests.cpp
index 9fe1f4d11..ed6a0aa91 100644
--- a/components/service/attestation/test/service/attestation_service_tests.cpp
+++ b/components/service/attestation/test/service/attestation_service_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,37 +19,38 @@ TEST_GROUP(AttestationServiceTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_attest_service_context = NULL;
service_locator_init();
m_attest_service_context =
- service_locator_query("sn:trustedfirmware.org:attestation:0", &status);
+ service_locator_query("sn:trustedfirmware.org:attestation:0");
CHECK_TRUE(m_attest_service_context);
- m_rpc_session_handle =
- service_context_open(m_attest_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session =
+ service_context_open(m_attest_service_context);
+ CHECK_TRUE(m_rpc_session);
- psa_iat_client_init(caller);
+ psa_iat_client_init(m_rpc_session);
}
void teardown()
{
psa_iat_client_deinit();
- service_context_close(m_attest_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_attest_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_attest_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_attest_service_context);
- m_attest_service_context = NULL;
+ service_context_relinquish(m_attest_service_context);
+ m_attest_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_attest_service_context;
};
diff --git a/components/service/block_storage/block_store/block_store.c b/components/service/block_storage/block_store/block_store.c
new file mode 100644
index 000000000..78be43d29
--- /dev/null
+++ b/components/service/block_storage/block_store/block_store.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include "block_store.h"
+
+psa_status_t block_store_get_partition_info(struct block_store *block_store,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ assert(block_store);
+ assert(block_store->interface);
+
+ return block_store->interface->get_partition_info(block_store->context,
+ partition_guid,
+ info);
+}
+
+psa_status_t block_store_open(struct block_store *block_store,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ assert(block_store);
+ assert(block_store->interface);
+
+ return block_store->interface->open(block_store->context,
+ client_id,
+ partition_guid,
+ handle);
+}
+
+psa_status_t block_store_close(struct block_store *block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ assert(block_store);
+ assert(block_store->interface);
+
+ return block_store->interface->close(block_store->context,
+ client_id,
+ handle);
+}
+
+psa_status_t block_store_read(struct block_store *block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len)
+{
+ assert(block_store);
+ assert(block_store->interface);
+
+ return block_store->interface->read(block_store->context,
+ client_id,
+ handle,
+ lba,
+ offset,
+ buffer_size,
+ buffer,
+ data_len);
+}
+
+psa_status_t block_store_write(struct block_store *block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written)
+{
+ assert(block_store);
+ assert(block_store->interface);
+
+ return block_store->interface->write(block_store->context,
+ client_id,
+ handle,
+ lba,
+ offset,
+ data,
+ data_len,
+ num_written);
+}
+
+psa_status_t block_store_erase(struct block_store *block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks)
+{
+ assert(block_store);
+ assert(block_store->interface);
+
+ return block_store->interface->erase(block_store->context,
+ client_id,
+ handle,
+ begin_lba,
+ num_blocks);
+}
diff --git a/components/service/block_storage/block_store/block_store.h b/components/service/block_storage/block_store/block_store.h
new file mode 100644
index 000000000..e84972990
--- /dev/null
+++ b/components/service/block_storage/block_store/block_store.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BLOCK_STORE_H
+#define BLOCK_STORE_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "psa/error.h"
+#include "common/uuid/uuid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Opaque storage partition handle
+ *
+ * An opaque handle to a storage partition opened with a block_store. The meaning of
+ * the handle is private to the concrete block_store that issued the handle.
+ */
+typedef uint32_t storage_partition_handle_t;
+
+/**
+ * \brief Information about a storage partition
+ *
+ * A structure that holds information about the storage partition identified
+ * by the specified unique partition GUID.
+ */
+struct storage_partition_info
+{
+ /* Number of contiguous blocks from LBA zero */
+ size_t num_blocks;
+
+ /* Block size in bytes */
+ size_t block_size;
+
+ /* The unique partition GUID */
+ struct uuid_octets partition_guid;
+
+ /* GUID of the parent partition/device e.g. the disk GUID of the disk that
+ * contains the subject storage partition. A nil UUID should be returned if
+ * there is no parent.
+ */
+ struct uuid_octets parent_guid;
+};
+
+/**
+ * \brief Base block_store interface
+ *
+ * The block_store_interface structure provides a common interface for
+ * accessing a block-level storage device. A concrete block_store provides
+ * an implementation of this interface. A block_store provides access to
+ * one or more storage partitions, each identified by a unique GUID.
+ */
+struct block_store_interface
+{
+ /**
+ * \brief Get information about a partition
+ *
+ * \param[in] context The concrete block_store context
+ * \param[in] partition_guid Identifies the storage partition
+ * \param[out] info The partition info structure
+ *
+ * \return A status indicating whether the operation succeeded or not.
+ *
+ * \retval PSA_SUCCESS Operation completed successfully
+ * \retval PSA_ERROR_INVALID_ARGUMENT Unrecognized partition GUID
+ */
+ psa_status_t (*get_partition_info)(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info);
+
+ /**
+ * \brief Open a storage partition identified by its unique partition GUID.
+ *
+ * \param[in] context The concrete block_store context
+ * \param[in] client_id The requesting client ID
+ * \param[in] partition_guid Identifies the storage partition
+ * \param[out] handle The handle to use during the open partition
+ *
+ * \return A status indicating whether the operation succeeded or not.
+ *
+ * \retval PSA_SUCCESS Operation completed successfully
+ * \retval PSA_ERROR_NOT_PERMITTED Access not permitted
+ * \retval PSA_ERROR_INVALID_ARGUMENT At least one parameter is invalid
+ */
+ psa_status_t (*open)(void *context,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle);
+
+ /**
+ * \brief Close a previously opened storage partition.
+ *
+ * \param[in] context The concrete block_store context
+ * \param[in] client_id The requesting client ID
+ * \param[in] handle The handle corresponding to the partition to close
+ *
+ * \return A status indicating whether the operation succeeded or not.
+ *
+ * \retval PSA_SUCCESS Operation completed successfully
+ * \retval PSA_ERROR_INVALID_ARGUMENT Invalid handle
+ */
+ psa_status_t (*close)(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle);
+
+ /**
+ * \brief Read a block
+ *
+ * \param[in] context The concrete block_store context
+ * \param[in] client_id The requesting client ID
+ * \param[in] handle The handle corresponding to the open storage partition
+ * \param[in] lba The logical block address
+ * \param[in] offset Offset into the block at which to begin reading
+ * \param[in] buffer_size The size of the client provided buffer
+ * \param[in] buffer The buffer to land read data into
+ * \param[out] data_len The number of bytes read.
+ *
+ * \return A status indicating whether the operation succeeded or not.
+ *
+ * \retval PSA_SUCCESS Operation completed successfully
+ * \retval PSA_ERROR_INVALID_ARGUMENT Invalid parameter e.g. LBA is invalid
+ * \retval PSA_ERROR_BUFFER_TOO_SMALL Buffer not big enough
+ */
+ psa_status_t (*read)(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len);
+
+ /**
+ * \brief Write a block
+ *
+ * \param[in] context The concrete block_store context
+ * \param[in] client_id The requesting client ID
+ * \param[in] handle The handle corresponding to the open storage partition
+ * \param[in] lba The logical block address
+ * \param[in] offset Offset into the block at which to begin writing
+ * \param[in] data The data to write
+ * \param[in] data_len The number of bytes to write.
+ * \param[out] num_written The number of bytes written.
+ *
+ * \return A status indicating whether the operation succeeded or not.
+ *
+ * \retval PSA_SUCCESS Operation completed successfully
+ * \retval PSA_ERROR_INVALID_ARGUMENT Invalid parameter e.g. LBA is invalid
+ */
+ psa_status_t (*write)(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written);
+
+ /**
+ * \brief Erase a set of contiguous blocks
+ *
+ * Erase the specified set of contiguous blocks. If a storage technology does not explicitly
+ * support erase but instead, performs erase on write, a concrete block_store should silently
+ * do nothing on erase and always return PSA_SUCCESS. If an end_lba is specified that is
+ * beyond the last block in the partition, the range of erased blocks will be clipped to
+ * the end of the partition.
+ *
+ * \param[in] context The concrete block_store context
+ * \param[in] client_id The requesting client ID
+ * \param[in] handle The handle corresponding to the open storage partition
+ * \param[in] begin_lba LBA of first block to erase
+ * \param[in] num_blocks Number of contiguous blocks to erase
+ *
+ * \return A status indicating whether the operation succeeded or not.
+ *
+ * \retval PSA_SUCCESS Operation completed successfully
+ * \retval PSA_ERROR_INVALID_ARGUMENT Invalid parameter e.g. LBA is invalid
+ */
+ psa_status_t (*erase)(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks);
+};
+
+/**
+ * \brief Base block_store structure
+ *
+ * A concrete block store is responsible for initializing this structure to
+ * enable the block store to be accessed via the generic block_store_interface
+ * function pointers.
+ */
+struct block_store
+{
+ /**
+ * \brief The opaque context
+ *
+ * This is a pointer to the instance data of a block_store specialization that
+ * realizes the block_store interface. The concrete type of the pointer is specific
+ * to the specialization.
+ */
+ void *context;
+
+ /**
+ * \brief Pointer to a concrete block_store_interface
+ */
+ const struct block_store_interface *interface;
+};
+
+/**
+ * \brief Public interface functions for calling concrete block_store functions
+ *
+ */
+psa_status_t block_store_get_partition_info(struct block_store *block_store,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info);
+
+psa_status_t block_store_open(struct block_store *block_store,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle);
+
+psa_status_t block_store_close(struct block_store *block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle);
+
+psa_status_t block_store_read(struct block_store *block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len);
+
+psa_status_t block_store_write(struct block_store *block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written);
+
+psa_status_t block_store_erase(struct block_store *block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLOCK_STORE_H */
diff --git a/components/service/block_storage/block_store/client/block_storage_client.c b/components/service/block_storage/block_store/client/block_storage_client.c
new file mode 100644
index 000000000..ec741aa9f
--- /dev/null
+++ b/components/service/block_storage/block_store/client/block_storage_client.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rpc_caller_session.h"
+#include "block_storage_client.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "protocols/service/block_storage/packed-c/messages.h"
+#include "protocols/service/block_storage/packed-c/opcodes.h"
+
+static psa_status_t block_storage_client_get_partition_info(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ struct block_storage_client *this_context = (struct block_storage_client *)context;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ struct ts_block_storage_get_partition_info_in req_msg = {0};
+ size_t req_len = sizeof(req_msg);
+ uint8_t *req_buf = NULL;
+
+ memcpy(req_msg.partition_guid, partition_guid->octets, sizeof(req_msg.partition_guid));
+
+ rpc_call_handle call_handle =
+ rpc_caller_session_begin(this_context->client.session, &req_buf, req_len,
+ sizeof(struct ts_block_storage_get_partition_info_out));
+
+ if (call_handle) {
+ uint8_t *resp_buf = NULL;
+ size_t resp_len = 0;
+ service_status_t service_status = 0;
+
+ memcpy(req_buf, &req_msg, req_len);
+
+ this_context->client.rpc_status = rpc_caller_session_invoke(
+ call_handle, TS_BLOCK_STORAGE_OPCODE_GET_PARTITION_INFO, &resp_buf,
+ &resp_len, &service_status);
+
+ if (this_context->client.rpc_status == RPC_SUCCESS) {
+
+ psa_status = service_status;
+
+ if (psa_status == PSA_SUCCESS) {
+
+ if (resp_len >=
+ sizeof(struct ts_block_storage_get_partition_info_out)) {
+
+ struct ts_block_storage_get_partition_info_out resp_msg;
+
+ memcpy(&resp_msg, resp_buf, sizeof(resp_msg));
+
+ info->block_size = resp_msg.block_size;
+ info->num_blocks = resp_msg.num_blocks;
+
+ memcpy(info->partition_guid.octets,
+ resp_msg.partition_guid,
+ TS_BLOCK_STORAGE_GUID_OCTET_LEN);
+
+ memcpy(info->parent_guid.octets,
+ resp_msg.parent_guid,
+ TS_BLOCK_STORAGE_GUID_OCTET_LEN);
+ }
+ else {
+ /* Failed to decode response message */
+ psa_status = PSA_ERROR_GENERIC_ERROR;
+ }
+ }
+ }
+
+ rpc_caller_session_end(call_handle);
+ } else {
+
+ this_context->client.rpc_status = RPC_ERROR_INTERNAL;
+ }
+
+ return psa_status;
+}
+
+static psa_status_t block_storage_client_open(void *context,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ struct block_storage_client *this_context = (struct block_storage_client *)context;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ struct ts_block_storage_open_in req_msg = {0};
+ size_t req_len = sizeof(req_msg);
+ uint8_t *req_buf = NULL;
+
+ (void)client_id;
+
+ memcpy(req_msg.partition_guid, partition_guid->octets, sizeof(req_msg.partition_guid));
+
+ rpc_call_handle call_handle =
+ rpc_caller_session_begin(this_context->client.session, &req_buf, req_len,
+ sizeof(struct ts_block_storage_open_out));
+
+ if (call_handle) {
+
+ uint8_t *resp_buf = NULL;
+ size_t resp_len = 0;
+ service_status_t service_status = 0;
+
+ memcpy(req_buf, &req_msg, req_len);
+
+ this_context->client.rpc_status = rpc_caller_session_invoke(
+ call_handle, TS_BLOCK_STORAGE_OPCODE_OPEN, &resp_buf, &resp_len,
+ &service_status);
+
+ if (this_context->client.rpc_status == RPC_SUCCESS) {
+
+ psa_status = service_status;
+
+ if (psa_status == PSA_SUCCESS) {
+
+ if (resp_len >= sizeof(struct ts_block_storage_open_out)) {
+
+ struct ts_block_storage_open_out resp_msg;
+
+ memcpy(&resp_msg, resp_buf, sizeof(resp_msg));
+ *handle = resp_msg.handle;
+ } else {
+ /* Failed to decode response message */
+ psa_status = PSA_ERROR_GENERIC_ERROR;
+ }
+ }
+ }
+
+ rpc_caller_session_end(call_handle);
+ } else {
+
+ this_context->client.rpc_status = RPC_ERROR_INTERNAL;
+ }
+
+ return psa_status;
+}
+
+static psa_status_t block_storage_client_close(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ struct block_storage_client *this_context = (struct block_storage_client *)context;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ struct ts_block_storage_close_in req_msg = {0};
+ size_t req_len = sizeof(req_msg);
+ uint8_t *req_buf = NULL;
+
+ (void)client_id;
+
+ req_msg.handle = handle;
+
+ rpc_call_handle call_handle =
+ rpc_caller_session_begin(this_context->client.session, &req_buf, req_len, 0);
+
+ if (call_handle) {
+
+ uint8_t *resp_buf = NULL;
+ size_t resp_len = 0;
+ service_status_t service_status = 0;
+
+ memcpy(req_buf, &req_msg, req_len);
+
+ this_context->client.rpc_status = rpc_caller_session_invoke(
+ call_handle, TS_BLOCK_STORAGE_OPCODE_CLOSE,
+ &resp_buf, &resp_len, &service_status);
+
+ if (this_context->client.rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
+
+ rpc_caller_session_end(call_handle);
+ } else {
+
+ this_context->client.rpc_status = RPC_ERROR_INTERNAL;
+ }
+
+ return psa_status;
+}
+
+static psa_status_t block_storage_client_read(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len)
+{
+ struct block_storage_client *this_context = (struct block_storage_client *)context;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ struct ts_block_storage_read_in req_msg = {0};
+ size_t req_len = sizeof(req_msg);
+ uint8_t *req_buf = NULL;
+
+ (void)client_id;
+
+ *data_len = 0;
+
+ req_msg.handle = handle;
+ req_msg.lba = lba;
+ req_msg.offset = offset;
+ req_msg.len = buffer_size;
+
+ rpc_call_handle call_handle =
+ rpc_caller_session_begin(this_context->client.session, &req_buf, req_len,
+ buffer_size);
+
+ if (call_handle) {
+
+ uint8_t *resp_buf = NULL;
+ size_t resp_len = 0;
+ service_status_t service_status = 0;
+
+ memcpy(req_buf, &req_msg, req_len);
+
+ this_context->client.rpc_status = rpc_caller_session_invoke(
+ call_handle, TS_BLOCK_STORAGE_OPCODE_READ, &resp_buf, &resp_len,
+ &service_status);
+
+ if (this_context->client.rpc_status == RPC_SUCCESS) {
+
+ psa_status = service_status;
+
+ if (psa_status == PSA_SUCCESS) {
+
+ if (resp_len <= buffer_size) {
+
+ memcpy(buffer, resp_buf, resp_len);
+ *data_len = resp_len;
+ } else {
+
+ psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ }
+ }
+
+ rpc_caller_session_end(call_handle);
+ } else {
+
+ this_context->client.rpc_status = RPC_ERROR_INTERNAL;
+ }
+
+ return psa_status;
+}
+
+static psa_status_t block_storage_client_write(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written)
+{
+ struct block_storage_client *this_context = (struct block_storage_client *)context;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ struct ts_block_storage_write_in req_msg = {0};
+ size_t req_len = sizeof(req_msg) + data_len;
+ uint8_t *req_buf = NULL;
+
+ (void)client_id;
+
+ req_msg.handle = handle;
+ req_msg.lba = lba;
+ req_msg.offset = offset;
+
+ rpc_call_handle call_handle =
+ rpc_caller_session_begin(this_context->client.session, &req_buf, req_len,
+ sizeof(struct ts_block_storage_write_out));
+
+ if (call_handle) {
+ uint8_t *resp_buf = NULL;
+ size_t resp_len = 0;
+ service_status_t service_status = 0;
+
+ /* Copy fixed size message */
+ memcpy(req_buf, &req_msg, sizeof(req_msg));
+
+ /* Copy variable length data */
+ memcpy(&req_buf[sizeof(req_msg)], data, data_len);
+
+ this_context->client.rpc_status = rpc_caller_session_invoke(
+ call_handle, TS_BLOCK_STORAGE_OPCODE_WRITE,
+ &resp_buf, &resp_len, &service_status);
+
+ if (this_context->client.rpc_status == RPC_SUCCESS) {
+
+ psa_status = service_status;
+
+ if (psa_status == PSA_SUCCESS) {
+
+ if (resp_len >= sizeof(struct ts_block_storage_write_out)) {
+
+ struct ts_block_storage_write_out resp_msg;
+
+ memcpy(&resp_msg, resp_buf, sizeof(resp_msg));
+ *num_written = resp_msg.num_written;
+ } else {
+ /* Failed to decode response message */
+ psa_status = PSA_ERROR_GENERIC_ERROR;
+ }
+ }
+ }
+
+ rpc_caller_session_end(call_handle);
+ } else {
+
+ this_context->client.rpc_status = RPC_ERROR_INTERNAL;
+ }
+
+ return psa_status;
+}
+
+static psa_status_t block_storage_client_erase(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks)
+{
+ struct block_storage_client *this_context = (struct block_storage_client *)context;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ struct ts_block_storage_erase_in req_msg = {0};
+ size_t req_len = sizeof(req_msg);
+ uint8_t *req_buf = NULL;
+
+ (void)client_id;
+
+ req_msg.handle = handle;
+ req_msg.begin_lba = begin_lba;
+ req_msg.num_blocks = num_blocks;
+
+ rpc_call_handle call_handle =
+ rpc_caller_session_begin(this_context->client.session, &req_buf, req_len, 0);
+
+ if (call_handle) {
+
+ uint8_t *resp_buf = NULL;
+ size_t resp_len = 0;
+ service_status_t service_status = 0;
+
+ /* Copy fixed size message */
+ memcpy(req_buf, &req_msg, sizeof(req_msg));
+
+ this_context->client.rpc_status = rpc_caller_session_invoke(
+ call_handle, TS_BLOCK_STORAGE_OPCODE_ERASE,
+ &resp_buf, &resp_len, &service_status);
+
+ if (this_context->client.rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
+
+ rpc_caller_session_end(call_handle);
+ } else {
+
+ this_context->client.rpc_status = RPC_ERROR_INTERNAL;
+ }
+
+ return psa_status;
+}
+
+struct block_store *block_storage_client_init(
+ struct block_storage_client *block_storage_client,
+ struct rpc_caller_session *session)
+{
+ service_client_init(&block_storage_client->client, session);
+
+ /* Define concrete block store interface */
+ static const struct block_store_interface interface = {
+ block_storage_client_get_partition_info,
+ block_storage_client_open,
+ block_storage_client_close,
+ block_storage_client_read,
+ block_storage_client_write,
+ block_storage_client_erase
+ };
+
+ /* Initialize base block_store */
+ block_storage_client->base_block_store.context = block_storage_client;
+ block_storage_client->base_block_store.interface = &interface;
+
+ return &block_storage_client->base_block_store;
+}
+
+void block_storage_client_deinit(
+ struct block_storage_client *block_storage_client)
+{
+ service_client_deinit(&block_storage_client->client);
+}
diff --git a/components/service/block_storage/block_store/client/block_storage_client.h b/components/service/block_storage/block_store/client/block_storage_client.h
new file mode 100644
index 000000000..244a05f1f
--- /dev/null
+++ b/components/service/block_storage/block_store/client/block_storage_client.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BLOCK_STORAGE_CLIENT_H
+#define BLOCK_STORAGE_CLIENT_H
+
+#include "service/common/client/service_client.h"
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief block_storage_client structure
+ *
+ * A block_storage_client is a block_store that communicates with a remote block
+ * storage service provider. Used when block level storage is handled in a
+ * different environment from the client environment.
+ */
+struct block_storage_client {
+ struct block_store base_block_store;
+ struct service_client client;
+};
+
+/**
+ * \brief Initialize a block_storage_client
+ *
+ * \param[in] block_storage_client The subject block_storage_client
+ * \param[in] caller An rpc_caller for reaching the associated service provider
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *block_storage_client_init(
+ struct block_storage_client *block_storage_client,
+ struct rpc_caller_session *session);
+
+/**
+ * \brief De-initialize a block_storage_client
+ *
+ * Frees resource allocated during call to block_storage_client_init().
+ *
+ * \param[in] block_storage_client The subject block_storage_client
+ */
+void block_storage_client_deinit(
+ struct block_storage_client *block_storage_client);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLOCK_STORAGE_CLIENT_H */
diff --git a/components/service/block_storage/block_store/client/component.cmake b/components/service/block_storage/block_store/client/component.cmake
new file mode 100644
index 000000000..d15c692a3
--- /dev/null
+++ b/components/service/block_storage/block_store/client/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_storage_client.c"
+ )
diff --git a/components/service/block_storage/block_store/component.cmake b/components/service/block_storage/block_store/component.cmake
new file mode 100644
index 000000000..66a3242d6
--- /dev/null
+++ b/components/service/block_storage/block_store/component.cmake
@@ -0,0 +1,15 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_store.c"
+ "${CMAKE_CURRENT_LIST_DIR}/storage_partition.c"
+ "${CMAKE_CURRENT_LIST_DIR}/storage_partition_acl.c"
+ )
diff --git a/components/service/block_storage/block_store/device/block_device.c b/components/service/block_storage/block_store/device/block_device.c
new file mode 100644
index 000000000..c355e8246
--- /dev/null
+++ b/components/service/block_storage/block_store/device/block_device.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+#include "block_device.h"
+
+#define BLOCK_DEVICE_PARTITION_HANDLE (0)
+
+psa_status_t block_device_check_access_permitted(
+ const struct block_device *block_device,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ if (handle != BLOCK_DEVICE_PARTITION_HANDLE)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (!storage_partition_is_access_permitted(&block_device->storage_partition, client_id))
+ return PSA_ERROR_NOT_PERMITTED;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t block_device_get_partition_info(
+ struct block_device *block_device,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+
+ if (storage_partition_is_guid_matched(&block_device->storage_partition, partition_guid)) {
+
+ info->block_size = block_device->storage_partition.block_size;
+ info->num_blocks = block_device->storage_partition.num_blocks;
+ info->partition_guid = block_device->storage_partition.partition_guid;
+
+ /* A block_device has no parent so return a nil UUID */
+ memset(info->parent_guid.octets, 0, sizeof(info->parent_guid.octets));
+
+ status = PSA_SUCCESS;
+ }
+
+ return status;
+}
+
+psa_status_t block_device_open(
+ struct block_device *block_device,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ psa_status_t status = PSA_ERROR_NOT_PERMITTED;
+
+ if (storage_partition_is_guid_matched(&block_device->storage_partition,
+ partition_guid) &&
+ storage_partition_is_open_permitted(&block_device->storage_partition,
+ client_id, NULL)) {
+
+ *handle = BLOCK_DEVICE_PARTITION_HANDLE;
+ status = PSA_SUCCESS;
+ }
+
+ return status;
+}
+
+psa_status_t block_device_close(
+ struct block_device *block_device,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ psa_status_t status = block_device_check_access_permitted(block_device, client_id, handle);
+
+ return status;
+}
+
+struct block_store *block_device_init(
+ struct block_device *block_device,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size)
+{
+ /* block_device exposes a single storage partition that represents the
+ * underlying storage device */
+ storage_partition_init(
+ &block_device->storage_partition,
+ disk_guid, num_blocks, block_size);
+
+ return &block_device->base_block_store;
+}
+
+void block_device_deinit(
+ struct block_device *block_device)
+{
+ storage_partition_deinit(
+ &block_device->storage_partition);
+}
+
+void block_device_configure(
+ struct block_device *block_device,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size)
+{
+ storage_partition_init(
+ &block_device->storage_partition,
+ disk_guid, num_blocks, block_size);
+} \ No newline at end of file
diff --git a/components/service/block_storage/block_store/device/block_device.h b/components/service/block_storage/block_store/device/block_device.h
new file mode 100644
index 000000000..f179c72e7
--- /dev/null
+++ b/components/service/block_storage/block_store/device/block_device.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BLOCK_DEVICE_H
+#define BLOCK_DEVICE_H
+
+#include "service/block_storage/block_store/block_store.h"
+#include "service/block_storage/block_store/storage_partition.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief block_device structure
+ *
+ * A block_device is a block_store that provides block storage in some way. A
+ * block_device specializes the base block_store to provide a common base for
+ * block storage devices such as flash drivers. Because any block_device realizes
+ * the common block_store interface, it may be used in any situation where the
+ * upper layer uses the block_store interface. A block_device exposes a single
+ * storage partition that represents the physical storage presented by
+ * the block_device. The block size and number of blocks will have been discovered
+ * in some way or will have been provided via configuration data.
+ */
+struct block_device
+{
+ struct block_store base_block_store;
+ struct storage_partition storage_partition;
+};
+
+/**
+ * \brief Initialize a block_device
+ *
+ * If configuration parameters are known at initialisation, they may be
+ * provided to configure the block device. If not, pass zero values for
+ * unknown configuration parameters.
+ *
+ * \param[in] block_device The subject block_device
+ * \param[in] disk_guid The disk GUID (can be NULL)
+ * \param[in] num_blocks The number of contiguous blocks
+ * \param[in] block_size Block size in bytes
+ *
+ * \return Pointer to the base block_store or NULL on failure
+ */
+struct block_store *block_device_init(
+ struct block_device *block_device,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size);
+
+/**
+ * \brief De-initialize a block_device
+ *
+ * \param[in] block_device The subject block_device
+ */
+void block_device_deinit(
+ struct block_device *block_device);
+
+/**
+ * \brief Configure a block_device
+ *
+ * Configure an initialised block_device. Configuration parameters are assumed
+ * to have been sanity checked based on knowledge of the concrete block_device.
+ *
+ * \param[in] block_device The subject block_device
+ * \param[in] disk_guid The disk GUID (can be NULL)
+ * \param[in] num_blocks The number of contiguous blocks
+ * \param[in] block_size Block size in bytes
+ */
+void block_device_configure(
+ struct block_device *block_device,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size);
+
+/**
+ * \brief Check if access is permitted
+ *
+ * Called by concrete block devices to check if a client is permitted access.
+ *
+ * \param[in] block_device The subject block_device
+ * \param[in] client_id The requesting client ID
+ * \param[in] handle The handle presented by the client
+ *
+ * \return PSA_SUCCESS if access permitted
+ */
+psa_status_t block_device_check_access_permitted(
+ const struct block_device *block_device,
+ uint32_t client_id,
+ storage_partition_handle_t handle);
+
+/**
+ * \brief Get information about the block device
+ *
+ * Called by concrete block devices to get information about the storage devices
+ *
+ * \param[in] block_device The subject block_device
+ * \param[in] partition_guid The requested partition GUID
+ * \param[out] info The retrieved information about the storage device
+ *
+ * \return PSA_SUCCESS on success
+ */
+psa_status_t block_device_get_partition_info(
+ struct block_device *block_device,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info);
+
+/**
+ * \brief Open the block device
+ *
+ * Called by concrete block devices to obtain a handle to use the block device
+ *
+ * \param[in] block_device The subject block_device
+ * \param[in] client_id The requesting client ID
+ * \param[in] partition_guid The requested partition GUID
+ * \param[out] handle The handle to use for device access operations
+ *
+ * \return PSA_SUCCESS on success
+ */
+psa_status_t block_device_open(
+ struct block_device *block_device,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle);
+
+/**
+ * \brief Close the block device
+ *
+ * \param[in] block_device The subject block_device
+ * \param[in] client_id The requesting client ID
+ * \param[in] handle The handle obtained on open
+ *
+ * \return PSA_SUCCESS on success
+ */
+psa_status_t block_device_close(
+ struct block_device *block_device,
+ uint32_t client_id,
+ storage_partition_handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLOCK_DEVICE_H */
diff --git a/components/service/block_storage/block_store/device/component.cmake b/components/service/block_storage/block_store/device/component.cmake
new file mode 100644
index 000000000..3397458b9
--- /dev/null
+++ b/components/service/block_storage/block_store/device/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_device.c"
+ )
diff --git a/components/service/block_storage/block_store/device/file/component.cmake b/components/service/block_storage/block_store/device/file/component.cmake
new file mode 100644
index 000000000..b330197d1
--- /dev/null
+++ b/components/service/block_storage/block_store/device/file/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/file_block_store.c"
+ )
diff --git a/components/service/block_storage/block_store/device/file/file_block_store.c b/components/service/block_storage/block_store/device/file/file_block_store.c
new file mode 100644
index 000000000..e83432917
--- /dev/null
+++ b/components/service/block_storage/block_store/device/file/file_block_store.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "file_block_store.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#define ERASED_DATA_VAL (0xff)
+
+ssize_t file_length(FILE *fp)
+{
+ ssize_t size = -1;
+
+ if (!fseek(fp, 0, SEEK_END))
+ size = ftell(fp);
+
+ return size;
+}
+
+static psa_status_t seek(FILE *fp, ssize_t pos)
+{
+ if (fseek(fp, pos, SEEK_SET))
+ return PSA_ERROR_BAD_STATE;
+
+ return PSA_SUCCESS;
+}
+
+static psa_status_t prepare_for_read(const struct file_block_store *this_instance, uint32_t lba,
+ size_t offset, size_t requested_read_len,
+ size_t *adjusted_read_len)
+{
+ assert(this_instance);
+
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ ssize_t read_pos = lba * storage_partition->block_size + offset;
+ ssize_t file_len = file_length(this_instance->file_handle);
+
+ if (file_len >= 0) {
+ /* File exists so attempt to seek the read position to the requested LBA + offset */
+ if (read_pos <= file_len) {
+ size_t bytes_until_end_of_file = (size_t)(file_len - read_pos);
+ size_t bytes_until_end_of_block = storage_partition->block_size - offset;
+
+ size_t read_limit = (bytes_until_end_of_file < bytes_until_end_of_block) ?
+ bytes_until_end_of_file :
+ bytes_until_end_of_block;
+
+ *adjusted_read_len =
+ (requested_read_len < read_limit) ? requested_read_len : read_limit;
+
+ status = seek(this_instance->file_handle, read_pos);
+ } else {
+ /* Requested block is beyond the end of the file */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t write_erased(const struct file_block_store *this_instance, size_t pos,
+ size_t len)
+{
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+ size_t remaining_len = len;
+
+ assert(this_instance);
+
+ status = seek(this_instance->file_handle, pos);
+
+ while ((status == PSA_SUCCESS) && (remaining_len > 0)) {
+ size_t erase_len = (remaining_len < sizeof(this_instance->erase_buf)) ?
+ remaining_len :
+ sizeof(this_instance->erase_buf);
+
+ size_t write_len =
+ fwrite(this_instance->erase_buf, 1, erase_len, this_instance->file_handle);
+
+ if (write_len != erase_len)
+ status = PSA_ERROR_BAD_STATE;
+
+ remaining_len -= erase_len;
+ }
+
+ return status;
+}
+
+static psa_status_t prepare_for_write(const struct file_block_store *this_instance, uint32_t lba,
+ size_t offset, size_t requested_write_len,
+ size_t *adjusted_write_len)
+{
+ assert(this_instance);
+
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ size_t bytes_until_end_of_block = storage_partition->block_size - offset;
+ *adjusted_write_len = (requested_write_len < bytes_until_end_of_block) ?
+ requested_write_len :
+ bytes_until_end_of_block;
+
+ ssize_t write_pos = lba * storage_partition->block_size + offset;
+ ssize_t file_len = file_length(this_instance->file_handle);
+
+ if (file_len >= 0) {
+ if (write_pos > file_len) {
+ /* Writing beyond the current end-of-file so extend the file */
+ status = write_erased(this_instance, file_len, write_pos - file_len);
+ } else {
+ /* Writing over existing data */
+ status = seek(this_instance->file_handle, write_pos);
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t file_block_store_get_partition_info(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ struct file_block_store *this_instance = (struct file_block_store *)context;
+
+ return block_device_get_partition_info(&this_instance->base_block_device, partition_guid,
+ info);
+}
+
+static psa_status_t file_block_store_open(void *context, uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ struct file_block_store *this_instance = (struct file_block_store *)context;
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+
+ if (this_instance->file_handle > 0) {
+ status = block_device_open(&this_instance->base_block_device, client_id,
+ partition_guid, handle);
+ }
+
+ return status;
+}
+
+static psa_status_t file_block_store_close(void *context, uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ struct file_block_store *this_instance = (struct file_block_store *)context;
+
+ return block_device_close(&this_instance->base_block_device, client_id, handle);
+}
+
+static psa_status_t file_block_store_read(void *context, uint32_t client_id,
+ storage_partition_handle_t handle, uint64_t lba,
+ size_t offset, size_t buffer_size, uint8_t *buffer,
+ size_t *data_len)
+{
+ const struct file_block_store *this_instance = (struct file_block_store *)context;
+
+ psa_status_t status = block_device_check_access_permitted(&this_instance->base_block_device,
+ client_id, handle);
+
+ *data_len = 0;
+
+ if (status == PSA_SUCCESS) {
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+ size_t read_len = 0;
+
+ status = prepare_for_read(this_instance, lba, offset, buffer_size,
+ &read_len);
+
+ if (status == PSA_SUCCESS) {
+ *data_len = fread(buffer, 1, read_len, this_instance->file_handle);
+
+ if (*data_len != read_len)
+ status = PSA_ERROR_BAD_STATE;
+ }
+ } else
+ /* Block or offset outside of configured limits */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return status;
+}
+
+static psa_status_t file_block_store_write(void *context, uint32_t client_id,
+ storage_partition_handle_t handle, uint64_t lba,
+ size_t offset, const uint8_t *data, size_t data_len,
+ size_t *num_written)
+{
+ struct file_block_store *this_instance = (struct file_block_store *)context;
+
+ psa_status_t status = block_device_check_access_permitted(&this_instance->base_block_device,
+ client_id, handle);
+
+ *num_written = 0;
+
+ if (status == PSA_SUCCESS) {
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+ size_t adjusted_len = 0;
+
+ status = prepare_for_write(this_instance, lba, offset, data_len,
+ &adjusted_len);
+
+ if (status == PSA_SUCCESS) {
+ *num_written =
+ fwrite(data, 1, adjusted_len, this_instance->file_handle);
+
+ if (*num_written != adjusted_len)
+ status = PSA_ERROR_BAD_STATE;
+ }
+ } else
+ /* Block or offset outside of configured limits */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return status;
+}
+
+static psa_status_t file_block_store_erase(void *context, uint32_t client_id,
+ storage_partition_handle_t handle, uint64_t begin_lba,
+ size_t num_blocks)
+{
+ struct file_block_store *this_instance = (struct file_block_store *)context;
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ psa_status_t status = block_device_check_access_permitted(&this_instance->base_block_device,
+ client_id, handle);
+
+ /* Sanitize the range of LBAs to erase */
+ if ((status == PSA_SUCCESS) &&
+ !storage_partition_is_lba_legal(storage_partition, begin_lba))
+ status = PSA_ERROR_INVALID_ARGUMENT;
+
+ if (status == PSA_SUCCESS) {
+ size_t blocks_remaining = storage_partition->num_blocks - begin_lba;
+ size_t blocks_to_erase = (num_blocks < blocks_remaining) ? num_blocks :
+ blocks_remaining;
+
+ ssize_t file_len = file_length(this_instance->file_handle);
+
+ if (file_len >= 0) {
+ /* File exists. If erased block falls within the limits of the file,
+ * explicitly set blocks to the erased state. If erased block is
+ * beyond EOF, there's nothing to do.
+ */
+ ssize_t block_pos = begin_lba * storage_partition->block_size;
+
+ if (block_pos < file_len)
+ status = write_erased(this_instance, block_pos,
+ blocks_to_erase *
+ storage_partition->block_size);
+
+ } else {
+ status = PSA_ERROR_BAD_STATE;
+ }
+ }
+
+ return status;
+}
+
+struct block_store *file_block_store_init(struct file_block_store *this_instance,
+ const char *filename, size_t block_size)
+{
+ struct block_store *block_store = NULL;
+ size_t num_blocks = 0;
+
+ assert(this_instance);
+
+ /* Define concrete block store interface */
+ static const struct block_store_interface interface = { file_block_store_get_partition_info,
+ file_block_store_open,
+ file_block_store_close,
+ file_block_store_read,
+ file_block_store_write,
+ file_block_store_erase };
+
+ /* Initialize base block_store */
+ this_instance->base_block_device.base_block_store.context = this_instance;
+ this_instance->base_block_device.base_block_store.interface = &interface;
+
+ /* Initialize buffer used for erase operations */
+ memset(this_instance->erase_buf, ERASED_DATA_VAL, sizeof(this_instance->erase_buf));
+
+ /* Open the file */
+ this_instance->file_handle = fopen(filename, "r+b");
+
+ if (this_instance->file_handle) {
+ /* File already exists so initialise the view of the number of blocks */
+ ssize_t file_len = file_length(this_instance->file_handle);
+
+ if (file_len >= 0)
+ num_blocks = (size_t)file_len / block_size;
+
+ } else {
+ /* File doesn't exist so create an empty one */
+ this_instance->file_handle = fopen(filename, "w+b");
+ }
+
+ if (this_instance->file_handle)
+ block_store = block_device_init(&this_instance->base_block_device, NULL, num_blocks,
+ block_size);
+
+ return block_store;
+}
+
+void file_block_store_deinit(struct file_block_store *this_instance)
+{
+ assert(this_instance);
+
+ if (this_instance->file_handle) {
+ fclose(this_instance->file_handle);
+ this_instance->file_handle = NULL;
+ }
+
+ block_device_deinit(&this_instance->base_block_device);
+}
+
+psa_status_t file_block_store_configure(struct file_block_store *this_instance,
+ const struct uuid_octets *disk_guid, size_t num_blocks,
+ size_t block_size)
+{
+ assert(this_instance);
+
+ block_device_configure(&this_instance->base_block_device, disk_guid, num_blocks,
+ block_size);
+
+ return PSA_SUCCESS;
+}
diff --git a/components/service/block_storage/block_store/device/file/file_block_store.h b/components/service/block_storage/block_store/device/file/file_block_store.h
new file mode 100644
index 000000000..889b8e31c
--- /dev/null
+++ b/components/service/block_storage/block_store/device/file/file_block_store.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FILE_BLOCK_STORE_H
+#define FILE_BLOCK_STORE_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "service/block_storage/block_store/device/block_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief file_block_store structure
+ *
+ * A file_block_store is a block_device that uses a file for storage.
+ * The file represents a real storage device organized as a series of
+ * consecutive blocks. The file_block_store can be used for accessing disk
+ * image files in a Posix environment.
+ */
+struct file_block_store {
+ struct block_device base_block_device;
+ FILE *file_handle;
+ uint8_t erase_buf[256];
+};
+
+/**
+ * \brief Initialize a file_block_store
+ *
+ * \param[in] file_block_store The subject file_block_store
+ * \param[in] filename The host filename used for storage
+ * \param[in] block_size The storage block size
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *file_block_store_init(struct file_block_store *file_block_store,
+ const char *filename, size_t block_size);
+
+/**
+ * \brief De-initialize a file_block_store
+ *
+ * \param[in] file_block_store The subject file_block_store
+ */
+void file_block_store_deinit(struct file_block_store *file_block_store);
+
+/**
+ * \brief Configure the file_block_store
+ *
+ * \param[in] file_block_store The subject file_block_store
+ * \param[in] disk_guid The disk GUID (nil uuid for any)
+ * \param[in] num_blocks The number of contiguous blocks
+ * \param[in] block_size Block size in bytes
+ *
+ * \return PSA_SUCCESS if successful
+ */
+psa_status_t file_block_store_configure(struct file_block_store *file_block_store,
+ const struct uuid_octets *disk_guid, size_t num_blocks,
+ size_t block_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FILE_BLOCK_STORE_H */
diff --git a/components/service/block_storage/block_store/device/file/test/component.cmake b/components/service/block_storage/block_store/device/file/test/component.cmake
new file mode 100644
index 000000000..a587b5a85
--- /dev/null
+++ b/components/service/block_storage/block_store/device/file/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/file_block_store_tests.cpp"
+ )
diff --git a/components/service/block_storage/block_store/device/file/test/file_block_store_tests.cpp b/components/service/block_storage/block_store/device/file/test/file_block_store_tests.cpp
new file mode 100644
index 000000000..ca8777250
--- /dev/null
+++ b/components/service/block_storage/block_store/device/file/test/file_block_store_tests.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <cstdio>
+#include <cstring>
+#include <stdint.h>
+#include <string>
+
+#include "common/uuid/uuid.h"
+#include "service/block_storage/block_store/device/file/file_block_store.h"
+
+TEST_GROUP(FileBlockStoreTests)
+{
+ void setup()
+ {
+ m_filename = std::string("file_block_store.tmp");
+ memset(m_disk_guid.octets, 0, sizeof(m_disk_guid.octets));
+
+ struct block_store *block_store =
+ file_block_store_init(&m_file_block_store, m_filename.c_str(), BLOCK_SIZE);
+
+ CHECK_TRUE(block_store);
+
+ psa_status_t status = file_block_store_configure(&m_file_block_store, &m_disk_guid,
+ NUM_BLOCKS, BLOCK_SIZE);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_open(&m_file_block_store.base_block_device.base_block_store,
+ CLIENT_ID, &m_disk_guid, &m_partition_handle);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ void teardown()
+ {
+ block_store_close(&m_file_block_store.base_block_device.base_block_store, CLIENT_ID,
+ m_partition_handle);
+
+ file_block_store_deinit(&m_file_block_store);
+ remove(m_filename.c_str());
+ }
+
+ void set_block(size_t lba, size_t offset, size_t len, uint8_t val, size_t * num_written)
+ {
+ struct block_store *bs = &m_file_block_store.base_block_device.base_block_store;
+ uint8_t write_buf[len];
+
+ memset(write_buf, val, len);
+ *num_written = 0;
+
+ psa_status_t status = block_store_write(bs, CLIENT_ID, m_partition_handle, lba,
+ offset, write_buf, len, num_written);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ void check_block(size_t lba, size_t offset, size_t len, uint8_t expected_val)
+ {
+ struct block_store *bs = &m_file_block_store.base_block_device.base_block_store;
+ uint8_t read_buf[len];
+ size_t num_read = 0;
+
+ psa_status_t status = block_store_read(bs, CLIENT_ID, m_partition_handle, lba,
+ offset, len, read_buf, &num_read);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(len, num_read);
+
+ for (size_t i = 0; i < len; i++)
+ BYTES_EQUAL(expected_val, read_buf[i]);
+ }
+
+ void erase_blocks(uint32_t begin_lba, size_t num_blocks)
+ {
+ struct block_store *bs = &m_file_block_store.base_block_device.base_block_store;
+
+ psa_status_t status =
+ block_store_erase(bs, CLIENT_ID, m_partition_handle, begin_lba, num_blocks);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ static const size_t NUM_BLOCKS = 100;
+ static const size_t BLOCK_SIZE = 512;
+ static const uint32_t CLIENT_ID = 27;
+
+ std::string m_filename;
+ struct uuid_octets m_disk_guid;
+ struct file_block_store m_file_block_store;
+ storage_partition_handle_t m_partition_handle;
+};
+
+/*
+ * Check a sequence of whole block writes and reads.
+ */
+TEST(FileBlockStoreTests, wholeBlockRw)
+{
+ size_t num_written = 0;
+
+ set_block(7, 0, BLOCK_SIZE, 'a', &num_written);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, num_written);
+
+ set_block(6, 0, BLOCK_SIZE, 'b', &num_written);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, num_written);
+
+ set_block(1, 0, BLOCK_SIZE, 'c', &num_written);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, num_written);
+
+ set_block(9, 0, BLOCK_SIZE, 'd', &num_written);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, num_written);
+
+ /* Check written blocks are as expected */
+ check_block(7, 0, BLOCK_SIZE, 'a');
+ check_block(6, 0, BLOCK_SIZE, 'b');
+ check_block(1, 0, BLOCK_SIZE, 'c');
+ check_block(9, 0, BLOCK_SIZE, 'd');
+
+ /* Erase all the written blocks */
+ erase_blocks(9, 1);
+ erase_blocks(1, 1);
+ erase_blocks(7, 1);
+ erase_blocks(6, 1);
+}
+
+/*
+ * Check state when initialised with existing disk image file
+ */
+TEST(FileBlockStoreTests, initWithExistingDiskImage)
+{
+ /* Write to last block to expand disk image file to entire size */
+ size_t num_written = 0;
+
+ set_block(NUM_BLOCKS - 1, 0, BLOCK_SIZE, 'a', &num_written);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, num_written);
+
+ /* Close the block_store opened during setup. This will have created a disk image file */
+ block_store_close(&m_file_block_store.base_block_device.base_block_store, CLIENT_ID,
+ m_partition_handle);
+
+ file_block_store_deinit(&m_file_block_store);
+
+ /* Re-initialise and open */
+ struct block_store *block_store =
+ file_block_store_init(&m_file_block_store, m_filename.c_str(), BLOCK_SIZE);
+
+ CHECK_TRUE(block_store);
+
+ psa_status_t status =
+ block_store_open(block_store, CLIENT_ID, &m_disk_guid, &m_partition_handle);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Expect disk partition size to reflect existing disk file */
+ struct storage_partition_info disk_info;
+
+ status = block_store_get_partition_info(block_store, &m_disk_guid, &disk_info);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ UNSIGNED_LONGS_EQUAL(NUM_BLOCKS, disk_info.num_blocks);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, disk_info.block_size);
+}
diff --git a/components/service/block_storage/block_store/device/fvb/FirmwareVolumeBlock.h b/components/service/block_storage/block_store/device/fvb/FirmwareVolumeBlock.h
new file mode 100644
index 000000000..70350aae9
--- /dev/null
+++ b/components/service/block_storage/block_store/device/fvb/FirmwareVolumeBlock.h
@@ -0,0 +1,372 @@
+/** @file
+ This file provides control over block-oriented firmware devices.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference: PI
+ Version 1.0 and 1.2.
+
+**/
+
+#include <protocols/common/efi/efi_status.h>
+
+
+#ifndef __FIRMWARE_VOLUME_BLOCK_H__
+#define __FIRMWARE_VOLUME_BLOCK_H__
+
+/* Note: This is a temporarily fixed-up copy of the file from EDK2. This should
+ * replaced with one that is fetched from the upstream project at build-time to
+ * avoid duplication of EDK2 header files.
+ */
+#define IN
+#define OUT
+#define CONST const
+#define EFIAPI
+
+typedef efi_status_t EFI_STATUS;
+typedef uint32_t EFI_FVB_ATTRIBUTES_2;
+typedef uint64_t EFI_PHYSICAL_ADDRESS;
+typedef uint8_t UINT8;
+typedef uint64_t EFI_LBA;
+typedef unsigned int UINTN;
+typedef void* EFI_HANDLE;
+
+typedef struct _EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL;
+
+typedef EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL;
+
+/**
+ The GetAttributes() function retrieves the attributes and
+ current settings of the block.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
+ attributes and current settings are
+ returned. Type EFI_FVB_ATTRIBUTES_2 is defined
+ in EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were
+ returned.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_FVB_GET_ATTRIBUTES)(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+);
+
+
+/**
+ The SetAttributes() function sets configurable firmware volume
+ attributes and returns the new settings of the firmware volume.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes On input, Attributes is a pointer to
+ EFI_FVB_ATTRIBUTES_2 that contains the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. Type
+ EFI_FVB_ATTRIBUTES_2 is defined in
+ EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ @retval EFI_INVALID_PARAMETER The attributes requested are in
+ conflict with the capabilities
+ as declared in the firmware
+ volume header.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_FVB_SET_ATTRIBUTES)(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+);
+
+
+/**
+ The GetPhysicalAddress() function retrieves the base address of
+ a memory-mapped firmware volume. This function should be called
+ only for memory-mapped firmware volumes.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Address Pointer to a caller-allocated
+ EFI_PHYSICAL_ADDRESS that, on successful
+ return from GetPhysicalAddress(), contains the
+ base address of the firmware volume.
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_UNSUPPORTED The firmware volume is not memory mapped.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_FVB_GET_PHYSICAL_ADDRESS)(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+);
+
+/**
+ The GetBlockSize() function retrieves the size of the requested
+ block. It also returns the number of additional blocks with
+ the identical size. The GetBlockSize() function is used to
+ retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba Indicates the block for which to return the size.
+
+ @param BlockSize Pointer to a caller-allocated UINTN in which
+ the size of the block is returned.
+
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in
+ which the number of consecutive blocks,
+ starting with Lba, is returned. All
+ blocks in this range have a size of
+ BlockSize.
+
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_FVB_GET_BLOCK_SIZE)(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+);
+
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+ Implementations should be mindful that the firmware volume
+ might be in the ReadDisabled state. If it is in this state,
+ the Read() function must return the status code
+ EFI_ACCESS_DENIED without modifying the contents of the
+ buffer. The Read() function must also prevent spanning block
+ boundaries. If a read is requested that would span a block
+ boundary, the read must read up to the boundary but not
+ beyond. The output parameter NumBytes must be set to correctly
+ indicate the number of bytes actually read. The caller must be
+ aware that a read may be partially completed.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index
+ from which to read.
+
+ @param Offset Offset into the block at which to begin reading.
+
+ @param NumBytes Pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes read.
+
+ @param Buffer Pointer to a caller-allocated buffer that will
+ be used to hold the data that is read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully,
+ and contents are in Buffer.
+
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
+ boundary. On output, NumBytes
+ contains the total number of bytes
+ returned in Buffer.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ ReadDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is not
+ functioning correctly and could
+ not be read.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FVB_READ)(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+);
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ The Write() function writes the specified number of bytes from
+ the provided buffer to the specified block and offset. If the
+ firmware volume is sticky write, the caller must ensure that
+ all the bits of the specified range to write are in the
+ EFI_FVB_ERASE_POLARITY state before calling the Write()
+ function, or else the result will be unpredictable. This
+ unpredictability arises because, for a sticky-write firmware
+ volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
+ state but cannot flip it back again. Before calling the
+ Write() function, it is recommended for the caller to first call
+ the EraseBlocks() function to erase the specified block to
+ write. A block erase cycle will transition bits from the
+ (NOT)EFI_FVB_ERASE_POLARITY state back to the
+ EFI_FVB_ERASE_POLARITY state. Implementations should be
+ mindful that the firmware volume might be in the WriteDisabled
+ state. If it is in this state, the Write() function must
+ return the status code EFI_ACCESS_DENIED without modifying the
+ contents of the firmware volume. The Write() function must
+ also prevent spanning block boundaries. If a write is
+ requested that spans a block boundary, the write must store up
+ to the boundary but not beyond. The output parameter NumBytes
+ must be set to correctly indicate the number of bytes actually
+ written. The caller must be aware that a write may be
+ partially completed. All writes, partial or otherwise, must be
+ fully flushed to the hardware before the Write() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index to write to.
+
+ @param Offset Offset into the block at which to begin writing.
+
+ @param NumBytes The pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes actually written.
+
+ @param Buffer The pointer to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
+ LBA boundary. On output, NumBytes
+ contains the total number of bytes
+ actually written.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning
+ and could not be written.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_FVB_WRITE)(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+);
+
+
+
+
+///
+/// EFI_LBA_LIST_TERMINATOR
+///
+#define EFI_LBA_LIST_TERMINATOR 0xFFFFFFFFFFFFFFFFULL
+
+
+/**
+ Erases and initializes a firmware volume block.
+
+ The EraseBlocks() function erases one or more blocks as denoted
+ by the variable argument list. The entire parameter list of
+ blocks must be verified before erasing any blocks. If a block is
+ requested that does not exist within the associated firmware
+ volume (it has a larger index than the last block of the
+ firmware volume), the EraseBlocks() function must return the
+ status code EFI_INVALID_PARAMETER without modifying the contents
+ of the firmware volume. Implementations should be mindful that
+ the firmware volume might be in the WriteDisabled state. If it
+ is in this state, the EraseBlocks() function must return the
+ status code EFI_ACCESS_DENIED without modifying the contents of
+ the firmware volume. All calls to EraseBlocks() must be fully
+ flushed to the hardware before the EraseBlocks() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
+ instance.
+
+ @param ... The variable argument list is a list of tuples.
+ Each tuple describes a range of LBAs to erase
+ and consists of the following:
+ - An EFI_LBA that indicates the starting LBA
+ - A UINTN that indicates the number of blocks to
+ erase.
+
+ The list is terminated with an
+ EFI_LBA_LIST_TERMINATOR. For example, the
+ following indicates that two ranges of blocks
+ (5-7 and 10-11) are to be erased: EraseBlocks
+ (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
+
+ @retval EFI_SUCCESS The erase request successfully
+ completed.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning
+ correctly and could not be written.
+ The firmware device may have been
+ partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
+ in the variable argument list do
+ not exist in the firmware volume.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_FVB_ERASE_BLOCKS)(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+);
+
+///
+/// The Firmware Volume Block Protocol is the low-level interface
+/// to a firmware volume. File-level access to a firmware volume
+/// should not be done using the Firmware Volume Block Protocol.
+/// Normal access to a firmware volume must use the Firmware
+/// Volume Protocol. Typically, only the file system driver that
+/// produces the Firmware Volume Protocol will bind to the
+/// Firmware Volume Block Protocol.
+///
+struct _EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL{
+ EFI_FVB_GET_ATTRIBUTES GetAttributes;
+ EFI_FVB_SET_ATTRIBUTES SetAttributes;
+ EFI_FVB_GET_PHYSICAL_ADDRESS GetPhysicalAddress;
+ EFI_FVB_GET_BLOCK_SIZE GetBlockSize;
+ EFI_FVB_READ Read;
+ EFI_FVB_WRITE Write;
+ EFI_FVB_ERASE_BLOCKS EraseBlocks;
+ ///
+ /// The handle of the parent firmware volume.
+ ///
+ EFI_HANDLE ParentHandle;
+};
+
+
+#endif
diff --git a/components/service/block_storage/block_store/device/fvb/component.cmake b/components/service/block_storage/block_store/device/fvb/component.cmake
new file mode 100644
index 000000000..8d5036f76
--- /dev/null
+++ b/components/service/block_storage/block_store/device/fvb/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fvb_block_store.c"
+ )
diff --git a/components/service/block_storage/block_store/device/fvb/fvb_block_store.c b/components/service/block_storage/block_store/device/fvb/fvb_block_store.c
new file mode 100644
index 000000000..60d39f76b
--- /dev/null
+++ b/components/service/block_storage/block_store/device/fvb/fvb_block_store.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <trace.h>
+#include "fvb_block_store.h"
+
+
+static psa_status_t fvb_block_store_get_partition_info(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ struct fvb_block_store *this_instance = (struct fvb_block_store *)context;
+
+ return block_device_get_partition_info(&this_instance->base_block_device,
+ partition_guid, info);
+}
+
+static psa_status_t fvb_block_store_open(void *context,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ struct fvb_block_store *this_instance = (struct fvb_block_store *)context;
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+
+ if (this_instance->fvb_instance) {
+
+ status = block_device_open(&this_instance->base_block_device,
+ client_id, partition_guid, handle);
+ }
+
+ return status;
+}
+
+static psa_status_t fvb_block_store_close(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ struct fvb_block_store *this_instance = (struct fvb_block_store *)context;
+
+ return block_device_close(&this_instance->base_block_device, client_id, handle);
+}
+
+static psa_status_t fvb_block_store_read(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len)
+{
+ struct fvb_block_store *this_instance =(struct fvb_block_store *)context;
+ psa_status_t status = block_device_check_access_permitted(
+ &this_instance->base_block_device, client_id, handle);
+
+ *data_len = 0;
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *fvb = this_instance->fvb_instance;
+
+ if (!fvb)
+ return PSA_ERROR_BAD_STATE;
+
+ unsigned int num_bytes = buffer_size;
+ EFI_STATUS efi_status = fvb->Read(fvb, lba, offset, &num_bytes, buffer);
+
+ if (efi_status == EFI_SUCCESS) {
+
+ *data_len = num_bytes;
+ } else {
+
+ EMSG("FVB Read failed: %ld", efi_status);
+ status = PSA_ERROR_GENERIC_ERROR;
+ }
+ }
+ else {
+
+ /* Block or offset outside of configured limits */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t fvb_block_store_write(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written)
+{
+ struct fvb_block_store *this_instance = (struct fvb_block_store*)context;
+ psa_status_t status = block_device_check_access_permitted(
+ &this_instance->base_block_device, client_id, handle);
+
+ *num_written = 0;
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *fvb = this_instance->fvb_instance;
+
+ if (!fvb)
+ return PSA_ERROR_BAD_STATE;
+
+ unsigned int num_bytes = data_len;
+ EFI_STATUS efi_status = fvb->Write(fvb, lba, offset, &num_bytes, (UINT8 *)data);
+
+ if (efi_status == EFI_SUCCESS) {
+
+ *num_written = num_bytes;
+ } else {
+
+ EMSG("FVB Write failed: %ld", efi_status);
+ status = PSA_ERROR_GENERIC_ERROR;
+ }
+ }
+ else {
+
+ /* Block or offset outside of configured limits */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t fvb_block_store_erase(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks)
+{
+ struct fvb_block_store *this_instance = (struct fvb_block_store*)context;
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ psa_status_t status = block_device_check_access_permitted(
+ &this_instance->base_block_device, client_id, handle);
+
+ /* Sanitize the range of LBAs to erase */
+ if ((status == PSA_SUCCESS) &&
+ !storage_partition_is_lba_legal(storage_partition, begin_lba)) {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (status == PSA_SUCCESS) {
+
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *fvb = this_instance->fvb_instance;
+
+ if (!fvb)
+ return PSA_ERROR_BAD_STATE;
+
+ EFI_STATUS efi_status = fvb->EraseBlocks(fvb,
+ begin_lba, num_blocks, EFI_LBA_LIST_TERMINATOR);
+
+ if (efi_status != EFI_SUCCESS) {
+
+ EMSG("FVB Erase failed: %ld", efi_status);
+ status = PSA_ERROR_GENERIC_ERROR;
+ }
+ }
+
+ return status;
+}
+
+struct block_store *fvb_block_store_init(
+ struct fvb_block_store *this_instance,
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *fvb_instance)
+{
+ assert(this_instance);
+ assert(fvb_instance);
+
+ struct block_store *block_store = NULL;
+
+ this_instance->fvb_instance = fvb_instance;
+
+ /* Define concrete block store interface */
+ static const struct block_store_interface interface =
+ {
+ fvb_block_store_get_partition_info,
+ fvb_block_store_open,
+ fvb_block_store_close,
+ fvb_block_store_read,
+ fvb_block_store_write,
+ fvb_block_store_erase
+ };
+
+ /* Initialize base block_store */
+ this_instance->base_block_device.base_block_store.context = this_instance;
+ this_instance->base_block_device.base_block_store.interface = &interface;
+
+ /* Retrieve size information from the FVB driver */
+ unsigned int num_blocks = 0;
+ unsigned int block_size = 0;
+
+ EFI_STATUS efi_status = fvb_instance->GetBlockSize(fvb_instance,
+ 0, &block_size, &num_blocks);
+
+ if (efi_status == EFI_SUCCESS) {
+
+ block_store = block_device_init(&this_instance->base_block_device,
+ NULL, num_blocks, block_size);
+ } else {
+
+ this_instance->fvb_instance = NULL;
+ EMSG("FVB GetBlockSize failed: %ld", efi_status);
+ }
+
+ return block_store;
+}
+
+void fvb_block_store_deinit(
+ struct fvb_block_store *this_instance)
+{
+ this_instance->fvb_instance = NULL;
+
+ block_device_deinit(&this_instance->base_block_device);
+}
diff --git a/components/service/block_storage/block_store/device/fvb/fvb_block_store.h b/components/service/block_storage/block_store/device/fvb/fvb_block_store.h
new file mode 100644
index 000000000..43cdf8f1b
--- /dev/null
+++ b/components/service/block_storage/block_store/device/fvb/fvb_block_store.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FVB_BLOCK_STORE_H
+#define FVB_BLOCK_STORE_H
+
+#include <stdint.h>
+#include "service/block_storage/block_store/device/block_device.h"
+#include "FirmwareVolumeBlock.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * \brief fvb_block_store structure
+ *
+ * A fvb_block_store is a block_device that uses an instance of an EFI FVB driver
+ * to access storage. Acts as an adapter to allow for reuse of drivers from external
+ * projects such as edk2-platforms.
+ */
+struct fvb_block_store
+{
+ struct block_device base_block_device;
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *fvb_instance;
+};
+
+/**
+ * \brief Initialize a fvb_block_store
+ *
+ * \param[in] fvb_block_store The subject fvb_block_store
+ * \param[in] fvb_instance The fvb instance
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *fvb_block_store_init(
+ struct fvb_block_store *fvb_block_store,
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *fvb_instance);
+
+/**
+ * \brief De-initialize a fvb_block_store
+ *
+ * \param[in] fvb_block_store The subject fvb_block_store
+ */
+void fvb_block_store_deinit(
+ struct fvb_block_store *fvb_block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FVB_BLOCK_STORE_H */
diff --git a/components/service/block_storage/block_store/device/null/component.cmake b/components/service/block_storage/block_store/device/null/component.cmake
new file mode 100644
index 000000000..50a102c04
--- /dev/null
+++ b/components/service/block_storage/block_store/device/null/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/null_block_store.c"
+ )
diff --git a/components/service/block_storage/block_store/device/null/null_block_store.c b/components/service/block_storage/block_store/device/null/null_block_store.c
new file mode 100644
index 000000000..9b22b4f63
--- /dev/null
+++ b/components/service/block_storage/block_store/device/null/null_block_store.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+#include "null_block_store.h"
+
+static psa_status_t null_block_store_get_partition_info(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ struct null_block_store *null_block_store = (struct null_block_store*)context;
+ return block_device_get_partition_info(
+ &null_block_store->base_block_device, partition_guid, info);
+}
+
+static psa_status_t null_block_store_open(void *context,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ struct null_block_store *null_block_store = (struct null_block_store*)context;
+ return block_device_open(
+ &null_block_store->base_block_device, client_id, partition_guid, handle);
+}
+
+static psa_status_t null_block_store_close(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ struct null_block_store *null_block_store = (struct null_block_store*)context;
+ return block_device_close(
+ &null_block_store->base_block_device, client_id, handle);
+}
+
+static psa_status_t null_block_store_read(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len)
+{
+ const struct null_block_store *null_block_store = (struct null_block_store*)context;
+ psa_status_t status = block_device_check_access_permitted(
+ &null_block_store->base_block_device, client_id, handle);
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *storage_partition =
+ &null_block_store->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+
+ /* Just real zeros */
+ size_t bytes_remaining = storage_partition->block_size - offset;
+ size_t bytes_to_read = (buffer_size < bytes_remaining) ?
+ buffer_size :
+ bytes_remaining;
+
+ memset(buffer, 0, bytes_to_read);
+ *data_len = bytes_to_read;
+ }
+ else {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t null_block_store_write(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written)
+{
+ struct null_block_store *null_block_store = (struct null_block_store*)context;
+ psa_status_t status = block_device_check_access_permitted(
+ &null_block_store->base_block_device, client_id, handle);
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *storage_partition =
+ &null_block_store->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+
+ /* Don't actually write anything */
+ size_t bytes_remaining = storage_partition->block_size - offset;
+ size_t bytes_to_write = (data_len < bytes_remaining) ?
+ data_len :
+ bytes_remaining;
+
+ *num_written = bytes_to_write;
+ }
+ else {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t null_block_store_erase(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks)
+{
+ struct null_block_store *null_block_store = (struct null_block_store*)context;
+ const struct storage_partition *storage_partition =
+ &null_block_store->base_block_device.storage_partition;
+ psa_status_t status = block_device_check_access_permitted(
+ &null_block_store->base_block_device, client_id, handle);
+
+ /* Sanitize the erase starting point */
+ if ((status == PSA_SUCCESS) &&
+ !storage_partition_is_lba_legal(storage_partition, begin_lba))
+ status = PSA_ERROR_INVALID_ARGUMENT;
+
+ /* Do nothing */
+
+ return status;
+}
+
+struct block_store *null_block_store_init(
+ struct null_block_store *null_block_store,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size)
+{
+ /* Define concrete block store interface */
+ static const struct block_store_interface interface =
+ {
+ null_block_store_get_partition_info,
+ null_block_store_open,
+ null_block_store_close,
+ null_block_store_read,
+ null_block_store_write,
+ null_block_store_erase
+ };
+
+ /* Initialize base block_store */
+ null_block_store->base_block_device.base_block_store.context = null_block_store;
+ null_block_store->base_block_device.base_block_store.interface = &interface;
+
+ return block_device_init(
+ &null_block_store->base_block_device, disk_guid, num_blocks, block_size);
+}
+
+void null_block_store_deinit(
+ struct null_block_store *null_block_store)
+{
+ block_device_deinit(&null_block_store->base_block_device);
+}
diff --git a/components/service/block_storage/block_store/device/null/null_block_store.h b/components/service/block_storage/block_store/device/null/null_block_store.h
new file mode 100644
index 000000000..8c4e84354
--- /dev/null
+++ b/components/service/block_storage/block_store/device/null/null_block_store.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef NULL_BLOCK_STORE_H
+#define NULL_BLOCK_STORE_H
+
+#include "service/block_storage/block_store/device/block_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief null_block_store structure
+ *
+ * A null_block_store is a block_device that will ignore write operations and
+ * always return zero for read blocks. Because there is no storage, a null_block_store
+ * can be any size and support any block size. It is intended to be used as a placeholder
+ * block device during integration.
+ */
+struct null_block_store
+{
+ struct block_device base_block_device;
+};
+
+/**
+ * \brief Initialize a null_block_store
+ *
+ * \param[in] null_block_store The subject null_block_store
+ * \param[in] disk_guid The disk GUID (nil uuid for any)
+ * \param[in] num_blocks The number of contiguous blocks
+ * \param[in] block_size Block size in bytes
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *null_block_store_init(
+ struct null_block_store *null_block_store,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size);
+
+/**
+ * \brief De-initialize a null_block_store
+ *
+ * \param[in] null_block_store The subject null_block_store
+ */
+void null_block_store_deinit(
+ struct null_block_store *null_block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NULL_BLOCK_STORE_H */
diff --git a/components/service/block_storage/block_store/device/ram/component.cmake b/components/service/block_storage/block_store/device/ram/component.cmake
new file mode 100644
index 000000000..ed044354f
--- /dev/null
+++ b/components/service/block_storage/block_store/device/ram/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ram_block_store.c"
+ )
diff --git a/components/service/block_storage/block_store/device/ram/ram_block_store.c b/components/service/block_storage/block_store/device/ram/ram_block_store.c
new file mode 100644
index 000000000..7c234ff7f
--- /dev/null
+++ b/components/service/block_storage/block_store/device/ram/ram_block_store.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ram_block_store.h"
+
+
+#define RAM_BLOCK_STORE_ERASED_VALUE (0xff)
+
+static bool is_block_erased(const struct ram_block_store *ram_block_store,
+ uint64_t lba,
+ size_t offset,
+ size_t len)
+{
+ bool is_erased = true;
+ size_t block_start_index =
+ ram_block_store->base_block_device.storage_partition.block_size * lba;
+ size_t block_end_index =
+ block_start_index + ram_block_store->base_block_device.storage_partition.block_size;
+
+ size_t index = block_start_index + offset;
+ size_t end_index = (index + len < block_end_index) ?
+ index + len :
+ block_end_index;
+
+ while (index < end_index) {
+
+ if (ram_block_store->ram_back_store[index] != RAM_BLOCK_STORE_ERASED_VALUE) {
+
+ is_erased = false;
+ break;
+ }
+
+ ++index;
+ }
+
+ return is_erased;
+}
+
+static psa_status_t ram_block_store_get_partition_info(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ struct ram_block_store *ram_block_store = (struct ram_block_store*)context;
+ return block_device_get_partition_info(
+ &ram_block_store->base_block_device, partition_guid, info);
+}
+
+static psa_status_t ram_block_store_open(void *context,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ struct ram_block_store *ram_block_store = (struct ram_block_store*)context;
+ return block_device_open(
+ &ram_block_store->base_block_device, client_id, partition_guid, handle);
+}
+
+static psa_status_t ram_block_store_close(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ struct ram_block_store *ram_block_store = (struct ram_block_store*)context;
+ return block_device_close(
+ &ram_block_store->base_block_device, client_id, handle);
+}
+
+static psa_status_t ram_block_store_read(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len)
+{
+ struct ram_block_store *ram_block_store = (struct ram_block_store*)context;
+ psa_status_t status = block_device_check_access_permitted(
+ &ram_block_store->base_block_device, client_id, handle);
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *storage_partition =
+ &ram_block_store->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+
+ size_t bytes_remaining = storage_partition->block_size - offset;
+ size_t bytes_to_read = (buffer_size < bytes_remaining) ?
+ buffer_size :
+ bytes_remaining;
+
+ const uint8_t *block_start =
+ &ram_block_store->ram_back_store[lba * storage_partition->block_size];
+
+ memcpy(buffer, &block_start[offset], bytes_to_read);
+ *data_len = bytes_to_read;
+ }
+ else {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t ram_block_store_write(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written)
+{
+ struct ram_block_store *ram_block_store = (struct ram_block_store*)context;
+ psa_status_t status = block_device_check_access_permitted(
+ &ram_block_store->base_block_device, client_id, handle);
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *storage_partition =
+ &ram_block_store->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+
+ if (!is_block_erased(ram_block_store, lba, offset, data_len))
+ return PSA_ERROR_STORAGE_FAILURE;
+
+ size_t bytes_remaining = storage_partition->block_size - offset;
+ uint8_t *block_start =
+ &ram_block_store->ram_back_store[lba * storage_partition->block_size];
+
+ size_t bytes_to_write = (data_len < bytes_remaining) ?
+ data_len :
+ bytes_remaining;
+
+ memcpy(&block_start[offset], data, bytes_to_write);
+ *num_written = bytes_to_write;
+ }
+ else {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t ram_block_store_erase(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks)
+{
+ struct ram_block_store *ram_block_store = (struct ram_block_store*)context;
+ const struct storage_partition *storage_partition =
+ &ram_block_store->base_block_device.storage_partition;
+ psa_status_t status = block_device_check_access_permitted(
+ &ram_block_store->base_block_device, client_id, handle);
+
+ /* Sanitize the range of LBAs to erase */
+ if ((status == PSA_SUCCESS) &&
+ !storage_partition_is_lba_legal(storage_partition, begin_lba)) {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (status == PSA_SUCCESS) {
+
+ size_t blocks_to_erase = storage_partition_clip_num_blocks(storage_partition,
+ begin_lba, num_blocks);
+
+ uint8_t *erase_from =
+ &ram_block_store->ram_back_store[begin_lba * storage_partition->block_size];
+ size_t erase_len =
+ blocks_to_erase * storage_partition->block_size;
+
+ memset(erase_from, RAM_BLOCK_STORE_ERASED_VALUE, erase_len);
+ }
+
+ return status;
+}
+
+struct block_store *ram_block_store_init(
+ struct ram_block_store *ram_block_store,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size)
+{
+ struct block_store *retval = NULL;
+
+ /* Define concrete block store interface */
+ static const struct block_store_interface interface =
+ {
+ ram_block_store_get_partition_info,
+ ram_block_store_open,
+ ram_block_store_close,
+ ram_block_store_read,
+ ram_block_store_write,
+ ram_block_store_erase
+ };
+
+ /* Publish the public interface */
+ ram_block_store->base_block_device.base_block_store.context = ram_block_store;
+ ram_block_store->base_block_device. base_block_store.interface = &interface;
+
+ /* Allocate storage and set all to the erased state */
+ size_t back_store_size = num_blocks * block_size;
+ ram_block_store->ram_back_store = (uint8_t*)malloc(back_store_size);
+
+ if (ram_block_store->ram_back_store) {
+
+ memset(ram_block_store->ram_back_store, RAM_BLOCK_STORE_ERASED_VALUE, back_store_size);
+
+ retval = block_device_init(
+ &ram_block_store->base_block_device, disk_guid, num_blocks, block_size);
+ }
+
+ return retval;
+}
+
+void ram_block_store_deinit(
+ struct ram_block_store *ram_block_store)
+{
+ free(ram_block_store->ram_back_store);
+
+ block_device_deinit(&ram_block_store->base_block_device);
+}
+
+psa_status_t ram_block_store_modify(
+ struct ram_block_store *ram_block_store,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len)
+{
+ const struct storage_partition *storage_partition =
+ &ram_block_store->base_block_device.storage_partition;
+
+ size_t back_store_size = storage_partition->block_size * storage_partition->num_blocks;
+
+ if (offset < back_store_size) {
+
+ size_t write_len = (offset + data_len < back_store_size) ?
+ data_len : back_store_size - offset;
+
+ memcpy(&ram_block_store->ram_back_store[offset], data, write_len);
+ } else
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ return PSA_SUCCESS;
+}
diff --git a/components/service/block_storage/block_store/device/ram/ram_block_store.h b/components/service/block_storage/block_store/device/ram/ram_block_store.h
new file mode 100644
index 000000000..2b847e4ab
--- /dev/null
+++ b/components/service/block_storage/block_store/device/ram/ram_block_store.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef RAM_BLOCK_STORE_H
+#define RAM_BLOCK_STORE_H
+
+#include "service/block_storage/block_store/device/block_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief ram_block_store structure
+ *
+ * A ram_block_store is a block_device that uses normal memory for block storage.
+ * It presents a single storage partition with the capacity specified at initialization.
+ * The ram_block_store is intended to be used in test integrations where a real
+ * NV block_store is either not available or is not needed.
+ */
+struct ram_block_store
+{
+ struct block_device base_block_device;
+ uint8_t *ram_back_store;
+};
+
+/**
+ * \brief Initialize a ram_block_store
+ *
+ * \param[in] ram_block_store The subject ram_block_store
+ * \param[in] disk_guid The disk GUID
+ * \param[in] num_blocks The number of contiguous blocks
+ * \param[in] block_size Block size in bytes
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *ram_block_store_init(
+ struct ram_block_store *ram_block_store,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size);
+
+/**
+ * \brief De-initialize a ram_block_store
+ *
+ * Frees resource allocated during call to ram_block_store_init().
+ *
+ * \param[in] ram_block_store The subject ram_block_store
+ */
+void ram_block_store_deinit(
+ struct ram_block_store *ram_block_store);
+
+/**
+ * \brief Modify the ram back store
+ *
+ * Test support function to allow the ram back store to be modified.
+ *
+ * \param[in] ram_block_store The subject ram_block_store
+ * \param[in] offset Byte offset from start of store
+ * \param[in] data Data to write
+ * \param[in] data_len Length of data to write
+ *
+ * \return PSA_SUCCESS on success
+ */
+psa_status_t ram_block_store_modify(
+ struct ram_block_store *ram_block_store,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RAM_BLOCK_STORE_H */
diff --git a/components/service/block_storage/block_store/device/ram/test/component.cmake b/components/service/block_storage/block_store/device/ram/test/component.cmake
new file mode 100644
index 000000000..9fa7a6c93
--- /dev/null
+++ b/components/service/block_storage/block_store/device/ram/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ram_block_store_tests.cpp"
+ )
diff --git a/components/service/block_storage/block_store/device/ram/test/ram_block_store_tests.cpp b/components/service/block_storage/block_store/device/ram/test/ram_block_store_tests.cpp
new file mode 100644
index 000000000..fa75ad076
--- /dev/null
+++ b/components/service/block_storage/block_store/device/ram/test/ram_block_store_tests.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstring>
+#include <stdint.h>
+#include "common/uuid/uuid.h"
+#include "service/block_storage/block_store/device/ram/ram_block_store.h"
+#include "CppUTest/TestHarness.h"
+
+TEST_GROUP(RamBlockStoreTests)
+{
+ void setup()
+ {
+ uuid_guid_octets_from_canonical(&m_partition_guid,
+ "6152f22b-8128-4c1f-981f-3bd279519907");
+
+ m_block_store = ram_block_store_init(&m_ram_block_store,
+ &m_partition_guid, NUM_BLOCKS, BLOCK_SIZE);
+
+ CHECK_TRUE(m_block_store);
+ }
+
+ void teardown()
+ {
+ ram_block_store_deinit(&m_ram_block_store);
+ }
+
+ static const size_t NUM_BLOCKS = 100;
+ static const size_t BLOCK_SIZE = 512;
+ static const uint32_t CLIENT_ID = 27;
+
+ struct uuid_octets m_partition_guid;
+ struct block_store *m_block_store;
+ struct ram_block_store m_ram_block_store;
+};
+
+TEST(RamBlockStoreTests, getPartitionInfo)
+{
+ struct storage_partition_info info;
+
+ psa_status_t status =
+ block_store_get_partition_info(m_block_store, &m_partition_guid, &info);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ LONGS_EQUAL(NUM_BLOCKS, info.num_blocks);
+ LONGS_EQUAL(BLOCK_SIZE, info.block_size);
+ MEMCMP_EQUAL(m_partition_guid.octets,
+ info.partition_guid.octets, sizeof(info.partition_guid.octets));
+}
+
+TEST(RamBlockStoreTests, openClose)
+{
+ storage_partition_handle_t handle;
+
+ psa_status_t status =
+ block_store_open(m_block_store, CLIENT_ID, &m_partition_guid, &handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, CLIENT_ID, handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
+
+TEST(RamBlockStoreTests, writeReadEraseBlock)
+{
+ storage_partition_handle_t handle;
+ uint8_t write_buffer[BLOCK_SIZE];
+ uint8_t read_buffer[BLOCK_SIZE];
+ size_t data_len = 0;
+ size_t num_written = 0;
+ uint64_t lba = 10;
+
+ psa_status_t status =
+ block_store_open(m_block_store, CLIENT_ID, &m_partition_guid, &handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Expect to be able to write to a block as all blocks are assumed to
+ * be in the erased state */
+ memset(write_buffer, 0xaa, BLOCK_SIZE);
+ status = block_store_write(m_block_store, CLIENT_ID, handle, lba,
+ 0, write_buffer, BLOCK_SIZE, &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, num_written);
+
+ /* Expect to read back the same data */
+ memset(read_buffer, 0, BLOCK_SIZE);
+ status = block_store_read(m_block_store, CLIENT_ID, handle, lba,
+ 0, BLOCK_SIZE, read_buffer, &data_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, data_len);
+ MEMCMP_EQUAL(write_buffer, read_buffer, BLOCK_SIZE);
+
+ /* Attempt to write the same block again without an erase. Expect this to fail. */
+ memset(write_buffer, 0xbb, BLOCK_SIZE);
+ status = block_store_write(m_block_store, CLIENT_ID, handle, lba,
+ 0, write_buffer, BLOCK_SIZE, &num_written);
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, status);
+
+ /* Erase the block */
+ status = block_store_erase(m_block_store, CLIENT_ID, handle, lba, 1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Write to an erased block should now work */
+ status = block_store_write(m_block_store, CLIENT_ID, handle, lba,
+ 0, write_buffer, BLOCK_SIZE, &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, num_written);
+
+ status = block_store_close(m_block_store, CLIENT_ID, handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
+
+TEST(RamBlockStoreTests, writeBiggerThanBlock)
+{
+ storage_partition_handle_t handle;
+ uint8_t write_buffer[BLOCK_SIZE + BLOCK_SIZE / 2];
+ uint8_t read_buffer[BLOCK_SIZE];
+ size_t data_len = 0;
+ size_t num_written = 0;
+ uint64_t lba = 10;
+
+ psa_status_t status =
+ block_store_open(m_block_store, CLIENT_ID, &m_partition_guid, &handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Try writing more than the block size. Expect the operation to succeed but
+ * that the written data is limited to the block size*/
+ memset(write_buffer, 0xaa, sizeof(write_buffer));
+ status = block_store_write(m_block_store, CLIENT_ID, handle, lba,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, num_written);
+
+ /* Expect to read back the same data upto the end of a block */
+ memset(read_buffer, 0, BLOCK_SIZE);
+ status = block_store_read(m_block_store, CLIENT_ID, handle, lba,
+ 0, BLOCK_SIZE, read_buffer, &data_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(BLOCK_SIZE, data_len);
+ MEMCMP_EQUAL(write_buffer, read_buffer, BLOCK_SIZE);
+
+ status = block_store_close(m_block_store, CLIENT_ID, handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
+
+TEST(RamBlockStoreTests, writeToInvalidBlock)
+{
+ storage_partition_handle_t handle;
+ uint8_t write_buffer[BLOCK_SIZE];
+ size_t num_written = 0;
+ uint64_t lba = NUM_BLOCKS + 7;
+
+ psa_status_t status =
+ block_store_open(m_block_store, CLIENT_ID, &m_partition_guid, &handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Write to block beyond the limits of the storage partition should fail */
+ memset(write_buffer, 0xaa, BLOCK_SIZE);
+ status = block_store_write(m_block_store, CLIENT_ID, handle, lba,
+ 0, write_buffer, BLOCK_SIZE, &num_written);
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+ status = block_store_close(m_block_store, CLIENT_ID, handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
+
+TEST(RamBlockStoreTests, eraseOperations)
+{
+ storage_partition_handle_t handle;
+
+ psa_status_t status =
+ block_store_open(m_block_store, CLIENT_ID, &m_partition_guid, &handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Erase all blocks */
+ status = block_store_erase(m_block_store, CLIENT_ID, handle, 0, NUM_BLOCKS);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Erase all blocks using a length that exceeds the partition limit - should clip */
+ status = block_store_erase(m_block_store, CLIENT_ID, handle, 0, UINT32_MAX);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Begin LBA is outside of partition */
+ status = block_store_erase(m_block_store, CLIENT_ID, handle, NUM_BLOCKS + 1, NUM_BLOCKS);
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+ status = block_store_close(m_block_store, CLIENT_ID, handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+} \ No newline at end of file
diff --git a/components/service/block_storage/block_store/device/rpmb/component.cmake b/components/service/block_storage/block_store/device/rpmb/component.cmake
new file mode 100644
index 000000000..58ab0f1f4
--- /dev/null
+++ b/components/service/block_storage/block_store/device/rpmb/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_block_store.c"
+ )
diff --git a/components/service/block_storage/block_store/device/rpmb/rpmb_block_store.c b/components/service/block_storage/block_store/device/rpmb/rpmb_block_store.c
new file mode 100644
index 000000000..7b139b0f2
--- /dev/null
+++ b/components/service/block_storage/block_store/device/rpmb/rpmb_block_store.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rpmb_block_store.h"
+#include "util.h"
+
+static psa_status_t rpmb_block_store_get_partition_info(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ struct rpmb_block_store *block_store = (struct rpmb_block_store *)context;
+
+ return block_device_get_partition_info(
+ &block_store->base_block_device, partition_guid, info);
+}
+
+static psa_status_t rpmb_block_store_open(void *context, uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ struct rpmb_block_store *block_store = (struct rpmb_block_store *)context;
+
+ if (!block_store)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ return block_device_open(&block_store->base_block_device, client_id, partition_guid,
+ handle);
+}
+
+static psa_status_t rpmb_block_store_close(void *context, uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ struct rpmb_block_store *block_store = (struct rpmb_block_store *)context;
+
+ if (!block_store)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ return block_device_close(&block_store->base_block_device, client_id, handle);
+}
+
+static psa_status_t rpmb_block_store_read(void *context, uint32_t client_id,
+ storage_partition_handle_t handle, uint64_t lba,
+ size_t offset, size_t buffer_size, uint8_t *buffer,
+ size_t *data_len)
+{
+ struct rpmb_block_store *block_store = (struct rpmb_block_store *)context;
+ const struct storage_partition *storage_partition = NULL;
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ uint8_t temp[RPMB_DATA_SIZE] = { 0 };
+ size_t block_count = 0;
+ size_t end_offset = 0;
+ size_t i = 0;
+
+ if (!block_store)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (offset >= RPMB_DATA_SIZE)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (ADD_OVERFLOW(offset, buffer_size, &end_offset))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ status = block_device_check_access_permitted(&block_store->base_block_device, client_id,
+ handle);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ storage_partition = &block_store->base_block_device.storage_partition;
+ block_count = ROUNDUP_DIV(end_offset, RPMB_DATA_SIZE);
+
+ *data_len = 0;
+
+ for (i = 0; i < block_count; i++) {
+ size_t copy_length = 0;
+
+ if (!storage_partition_is_lba_legal(storage_partition, lba + i))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ status = rpmb_frontend_read(block_store->frontend, lba + i, temp, 1);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ copy_length = MIN(buffer_size, sizeof(temp) - offset);
+ memcpy(buffer, temp + offset, copy_length);
+
+ buffer += copy_length;
+ buffer_size -= copy_length;
+ *data_len += copy_length;
+ offset = 0;
+ }
+
+ return status;
+}
+
+static psa_status_t rpmb_block_store_write(void *context, uint32_t client_id,
+ storage_partition_handle_t handle, uint64_t lba,
+ size_t offset, const uint8_t *data, size_t data_len,
+ size_t *num_written)
+{
+ struct rpmb_block_store *block_store = (struct rpmb_block_store *)context;
+ const struct storage_partition *storage_partition = NULL;
+ uint8_t temp[RPMB_DATA_SIZE] = { 0 };
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ size_t i = 0;
+ size_t block_count = 0;
+
+ if (!block_store)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ status = block_device_check_access_permitted(&block_store->base_block_device, client_id,
+ handle);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ storage_partition = &block_store->base_block_device.storage_partition;
+
+ block_count = ROUNDUP_DIV(offset + data_len, RPMB_DATA_SIZE);
+
+ for (i = 0; i < block_count; i++) {
+ size_t copy_length = 0;
+
+ if (!storage_partition_is_lba_legal(storage_partition, lba + i))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ copy_length = MIN(data_len, sizeof(temp) - offset);
+ if (copy_length != sizeof(temp)) {
+ status = rpmb_frontend_read(block_store->frontend, lba + i, temp, 1);
+ if (status != PSA_SUCCESS)
+ return status;
+ }
+
+ memcpy(temp + offset, data, copy_length);
+
+ status = rpmb_frontend_write(block_store->frontend, lba + i, temp, 1);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ data += copy_length;
+ data_len -= copy_length;
+ *num_written += copy_length;
+ offset = 0;
+ }
+
+ return status;
+}
+
+static psa_status_t rpmb_block_store_erase(void *context, uint32_t client_id,
+ storage_partition_handle_t handle, uint64_t begin_lba,
+ size_t num_blocks)
+{
+ (void)context;
+ (void)client_id;
+ (void)handle;
+ (void)begin_lba;
+ (void)num_blocks;
+
+ return PSA_SUCCESS;
+}
+
+struct block_store *rpmb_block_store_init(struct rpmb_block_store *block_store,
+ const struct uuid_octets *disk_guid,
+ struct rpmb_frontend *frontend)
+{
+ static const struct block_store_interface interface = {
+ rpmb_block_store_get_partition_info,
+ rpmb_block_store_open,
+ rpmb_block_store_close,
+ rpmb_block_store_read,
+ rpmb_block_store_write,
+ rpmb_block_store_erase
+ };
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ size_t num_blocks = 0;
+ size_t block_size = 0;
+
+ block_store->frontend = frontend;
+ block_store->base_block_device.base_block_store.context = block_store;
+ block_store->base_block_device.base_block_store.interface = &interface;
+
+ status = rpmb_frontend_block_count(frontend, &num_blocks);
+ if (status != PSA_SUCCESS)
+ return NULL;
+
+ status = rpmb_frontend_block_size(frontend, &block_size);
+ if (status != PSA_SUCCESS)
+ return NULL;
+
+ return block_device_init(&block_store->base_block_device, disk_guid, num_blocks,
+ block_size);
+}
+
+void rpmb_block_store_deinit(struct rpmb_block_store *block_store)
+{
+ /* TODO: close session */
+ block_device_deinit(&block_store->base_block_device);
+}
diff --git a/components/service/block_storage/block_store/device/rpmb/rpmb_block_store.h b/components/service/block_storage/block_store/device/rpmb/rpmb_block_store.h
new file mode 100644
index 000000000..2302faffb
--- /dev/null
+++ b/components/service/block_storage/block_store/device/rpmb/rpmb_block_store.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef RPMB_BLOCK_STORE_H
+#define RPMB_BLOCK_STORE_H
+
+#include "service/rpmb/frontend/rpmb_frontend.h"
+#include "service/block_storage/block_store/device/block_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief RPMB block store structure
+ *
+ * A rpmb_block_store is a block_device that uses the RPMB frontend to provide RPMB based
+ * storage
+ */
+struct rpmb_block_store {
+ struct block_device base_block_device;
+ struct rpmb_frontend *frontend;
+};
+
+/**
+ * \brief Initialize a RPMB blockstore
+ *
+ * \param[in] block_store The subject block_store
+ * \param[in] disk_guid The disk GUID
+ * \param[in] num_blocks The number of contiguous blocks
+ * \param[in] block_size Block size in bytes
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *rpmb_block_store_init(struct rpmb_block_store *block_store,
+ const struct uuid_octets *disk_guid,
+ struct rpmb_frontend *frontend);
+
+/**
+ * \brief De-initialize a RPMB blockstore
+ *
+ * Frees resource allocated during call to ram_block_store_init().
+ *
+ * \param[in] block_store The subject block_store
+ */
+void rpmb_block_store_deinit(struct rpmb_block_store *block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_BLOCK_STORE_H */
diff --git a/components/service/block_storage/block_store/device/semihosting/component.cmake b/components/service/block_storage/block_store/device/semihosting/component.cmake
new file mode 100644
index 000000000..0514314c5
--- /dev/null
+++ b/components/service/block_storage/block_store/device/semihosting/component.cmake
@@ -0,0 +1,17 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/semihosting_block_store.c"
+ )
+
+set_property(TARGET ${TGT} APPEND PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
+ "semihosting"
+ ) \ No newline at end of file
diff --git a/components/service/block_storage/block_store/device/semihosting/semihosting_block_store.c b/components/service/block_storage/block_store/device/semihosting/semihosting_block_store.c
new file mode 100644
index 000000000..f65f598d7
--- /dev/null
+++ b/components/service/block_storage/block_store/device/semihosting/semihosting_block_store.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <lib/semihosting.h>
+#include "semihosting_block_store.h"
+
+#define ERASED_DATA_VAL (0xff)
+
+static psa_status_t seek(long handle, ssize_t pos)
+{
+ /* Appears to return bogus error so ignore error code */
+ semihosting_file_seek(handle, pos);
+ return PSA_SUCCESS;
+}
+
+static psa_status_t prepare_for_read(
+ const struct semihosting_block_store *this_instance,
+ uint64_t lba, size_t offset,
+ size_t requested_read_len,
+ size_t *adjusted_read_len)
+{
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ ssize_t read_pos = lba * storage_partition->block_size + offset;
+ ssize_t file_len = semihosting_file_length(this_instance->file_handle);
+
+ if (file_len >= 0) {
+
+ /* File exists so attempt to seek the read position to the requested LBA + offset */
+ if (read_pos <= file_len) {
+
+ size_t bytes_until_end_of_file = (size_t)(file_len - read_pos);
+ size_t bytes_until_end_of_block = storage_partition->block_size - offset;
+
+ size_t read_limit = (bytes_until_end_of_file < bytes_until_end_of_block) ?
+ bytes_until_end_of_file :
+ bytes_until_end_of_block;
+
+ *adjusted_read_len = (requested_read_len < read_limit) ?
+ requested_read_len :
+ read_limit;
+
+ status = seek(this_instance->file_handle, read_pos);
+ }
+ else {
+
+ /* Requested block is beyond the end of the file */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t write_erased(
+ const struct semihosting_block_store *this_instance,
+ size_t pos,
+ size_t len)
+{
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+ size_t remaining_len = len;
+
+ status = seek(this_instance->file_handle, pos);
+
+ while ((status == PSA_SUCCESS) && (remaining_len > 0)) {
+
+ size_t erase_len = (remaining_len < sizeof(this_instance->erase_buf)) ?
+ remaining_len :
+ sizeof(this_instance->erase_buf);
+
+ size_t write_len = erase_len;
+
+ if (semihosting_file_write(this_instance->file_handle,
+ &write_len,
+ (const uintptr_t)this_instance->erase_buf)) {
+
+ status = PSA_ERROR_BAD_STATE;
+ }
+
+ remaining_len -= erase_len;
+ }
+
+ return status;
+}
+
+static psa_status_t prepare_for_write(
+ const struct semihosting_block_store *this_instance,
+ uint64_t lba, size_t offset,
+ size_t requested_write_len,
+ size_t *adjusted_write_len)
+{
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ size_t bytes_until_end_of_block = storage_partition->block_size - offset;
+ *adjusted_write_len = (requested_write_len < bytes_until_end_of_block) ?
+ requested_write_len :
+ bytes_until_end_of_block;
+
+ ssize_t write_pos = lba * storage_partition->block_size + offset;
+ ssize_t file_len = semihosting_file_length(this_instance->file_handle);
+
+ if (file_len >= 0) {
+
+ if (write_pos > file_len) {
+
+ /* Writing beyond the current end-of-file so extend the file */
+ status = write_erased(this_instance, file_len, write_pos - file_len);
+ }
+ else {
+
+ /* Writing over existing data */
+ status = seek(this_instance->file_handle, write_pos);
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t semihosting_block_store_get_partition_info(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ struct semihosting_block_store *this_instance = (struct semihosting_block_store*)context;
+
+ return block_device_get_partition_info(
+ &this_instance->base_block_device, partition_guid, info);
+}
+
+static psa_status_t semihosting_block_store_open(void *context,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ struct semihosting_block_store *this_instance = (struct semihosting_block_store*)context;
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+
+ if (this_instance->file_handle > 0) {
+
+ status = block_device_open(
+ &this_instance->base_block_device,
+ client_id, partition_guid, handle);
+ }
+
+ return status;
+}
+
+static psa_status_t semihosting_block_store_close(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ struct semihosting_block_store *this_instance = (struct semihosting_block_store*)context;
+
+ return block_device_close(
+ &this_instance->base_block_device, client_id, handle);
+}
+
+static psa_status_t semihosting_block_store_read(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len)
+{
+ const struct semihosting_block_store *this_instance =
+ (struct semihosting_block_store*)context;
+
+ psa_status_t status = block_device_check_access_permitted(
+ &this_instance->base_block_device, client_id, handle);
+
+ *data_len = 0;
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+
+ size_t read_len = 0;
+
+ status = prepare_for_read(
+ this_instance,
+ lba, offset,
+ buffer_size,
+ &read_len);
+
+ if (status == PSA_SUCCESS) {
+
+ if (!semihosting_file_read(this_instance->file_handle,
+ &read_len,
+ (uintptr_t)buffer)) {
+
+ *data_len = read_len;
+ }
+ else {
+
+ status = PSA_ERROR_BAD_STATE;
+ }
+ }
+ }
+ else {
+
+ /* Block or offset outside of configured limits */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t semihosting_block_store_write(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written)
+{
+ struct semihosting_block_store *this_instance = (struct semihosting_block_store*)context;
+ psa_status_t status = block_device_check_access_permitted(
+ &this_instance->base_block_device, client_id, handle);
+
+ *num_written = 0;
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ if (storage_partition_is_lba_legal(storage_partition, lba) &&
+ (offset < storage_partition->block_size)) {
+
+ size_t adjusted_len = 0;
+
+ status = prepare_for_write(
+ this_instance,
+ lba, offset,
+ data_len,
+ &adjusted_len);
+
+ if (status == PSA_SUCCESS) {
+
+ size_t write_len = adjusted_len;
+
+ if (!semihosting_file_write(this_instance->file_handle,
+ &write_len,
+ (uintptr_t)data)) {
+
+ *num_written = adjusted_len;
+ }
+ else {
+
+ status = PSA_ERROR_BAD_STATE;
+ }
+ }
+ }
+ else {
+
+ /* Block or offset outside of configured limits */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t semihosting_block_store_erase(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks)
+{
+ struct semihosting_block_store *this_instance = (struct semihosting_block_store*)context;
+ const struct storage_partition *storage_partition =
+ &this_instance->base_block_device.storage_partition;
+
+ psa_status_t status = block_device_check_access_permitted(
+ &this_instance->base_block_device, client_id, handle);
+
+ /* Sanitize the range of LBAs to erase */
+ if ((status == PSA_SUCCESS) &&
+ !storage_partition_is_lba_legal(storage_partition, begin_lba)) {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (status == PSA_SUCCESS) {
+
+ size_t blocks_remaining = storage_partition->num_blocks - begin_lba;
+ size_t blocks_to_erase = (num_blocks < blocks_remaining) ? num_blocks : blocks_remaining;
+
+ ssize_t file_len = semihosting_file_length(this_instance->file_handle);
+
+ if (file_len >= 0) {
+
+ /* File exists. If erased block falls within the limits of the file,
+ * explicitly set blocks to the erased state. If erased block is
+ * beyond EOF, there's nothing to do. */
+ ssize_t block_pos = begin_lba * storage_partition->block_size;
+
+ if (block_pos < file_len) {
+
+ status = write_erased(this_instance,
+ block_pos,
+ blocks_to_erase * storage_partition->block_size);
+ }
+ }
+ else {
+
+ status = PSA_ERROR_BAD_STATE;
+ }
+ }
+
+ return status;
+}
+
+struct block_store *semihosting_block_store_init(
+ struct semihosting_block_store *this_instance,
+ const char *filename,
+ size_t block_size)
+{
+ struct block_store *block_store = NULL;
+ size_t num_blocks = 0;
+
+ /* Define concrete block store interface */
+ static const struct block_store_interface interface =
+ {
+ semihosting_block_store_get_partition_info,
+ semihosting_block_store_open,
+ semihosting_block_store_close,
+ semihosting_block_store_read,
+ semihosting_block_store_write,
+ semihosting_block_store_erase
+ };
+
+ /* Initialize base block_store */
+ this_instance->base_block_device.base_block_store.context = this_instance;
+ this_instance->base_block_device.base_block_store.interface = &interface;
+
+ /* Initialize buffer used for erase operations */
+ memset(this_instance->erase_buf, ERASED_DATA_VAL, sizeof(this_instance->erase_buf));
+
+ long int file_len = semihosting_get_flen(filename);
+
+ if (file_len < 0) {
+
+ /* File doesn't exist so create an empty one. A call to
+ * semihosting_block_store_configure() will be needed to
+ * set the number of blocks and block size to make a viable
+ * block store. */
+ long handle = semihosting_file_open(filename, FOPEN_MODE_WPLUSB);
+ semihosting_file_close(handle);
+ }
+ else if (file_len > 0) {
+
+ /* There's an existing file with contents so this should be
+ * formatted to the intended size of the storage. */
+ num_blocks = (size_t)file_len / block_size;
+ }
+
+ /* Open host file for normal operation */
+ this_instance->file_handle = semihosting_file_open(
+ filename,
+ FOPEN_MODE_RPLUSB);
+
+ if (this_instance->file_handle > 0) {
+
+ block_store = block_device_init(
+ &this_instance->base_block_device, NULL, num_blocks, block_size);
+ }
+
+ return block_store;
+}
+
+void semihosting_block_store_deinit(
+ struct semihosting_block_store *this_instance)
+{
+ if (this_instance->file_handle > 0) {
+
+ semihosting_file_close(this_instance->file_handle);
+ this_instance->file_handle = 0;
+ }
+
+ block_device_deinit(&this_instance->base_block_device);
+}
+
+psa_status_t semihosting_block_store_configure(
+ struct semihosting_block_store *this_instance,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size)
+{
+ block_device_configure(&this_instance->base_block_device,
+ disk_guid, num_blocks, block_size);
+
+ return PSA_SUCCESS;
+}
+
+void semihosting_block_store_wipe(
+ const char *filename)
+{
+ /* If file exists and has contents, open with mode w+b to clear contents */
+ if (semihosting_get_flen(filename) > 0) {
+
+ long handle = semihosting_file_open(filename, FOPEN_MODE_WPLUSB);
+ semihosting_file_close(handle);
+ }
+} \ No newline at end of file
diff --git a/components/service/block_storage/block_store/device/semihosting/semihosting_block_store.h b/components/service/block_storage/block_store/device/semihosting/semihosting_block_store.h
new file mode 100644
index 000000000..7642251ff
--- /dev/null
+++ b/components/service/block_storage/block_store/device/semihosting/semihosting_block_store.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SEMIHOSTING_BLOCK_STORE_H
+#define SEMIHOSTING_BLOCK_STORE_H
+
+#include <stdint.h>
+#include "service/block_storage/block_store/device/block_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief semihosting_block_store structure
+ *
+ * A semihosting_block_store is a block_device that can be used on virtual
+ * platforms with semihosting capability to store blocks in a file residing
+ * in the host machine's filesystem. The file contains the raw block data
+ * which may include a partition header such as a GPT. The semihosting_block_store
+ * is agnostic about the file contents.
+ */
+struct semihosting_block_store
+{
+ struct block_device base_block_device;
+ long file_handle;
+ uint8_t erase_buf[256];
+};
+
+/**
+ * \brief Initialize a semihosting_block_store
+ *
+ * \param[in] semihosting_block_store The subject semihosting_block_store
+ * \param[in] filename The host filename used for storage
+ * \param[in] block_size The storage block size
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *semihosting_block_store_init(
+ struct semihosting_block_store *semihosting_block_store,
+ const char *filename,
+ size_t block_size);
+
+/**
+ * \brief De-initialize a semihosting_block_store
+ *
+ * \param[in] semihosting_block_store The subject semihosting_block_store
+ */
+void semihosting_block_store_deinit(
+ struct semihosting_block_store *semihosting_block_store);
+
+/**
+ * \brief Configure the semihosting_block_store
+ *
+ * \param[in] semihosting_block_store The subject semihosting_block_store
+ * \param[in] disk_guid The disk GUID (nil uuid for any)
+ * \param[in] num_blocks The number of contiguous blocks
+ * \param[in] block_size Block size in bytes
+ *
+ * \return PSA_SUCCESS if successful
+ */
+psa_status_t semihosting_block_store_configure(
+ struct semihosting_block_store *semihosting_block_store,
+ const struct uuid_octets *disk_guid,
+ size_t num_blocks,
+ size_t block_size);
+
+/**
+ * \brief Wipe contents of the block store
+ *
+ * Test support function to wipe the contents of the block store file.
+ *
+ * \param[in] filename The host filename used for storage
+ */
+void semihosting_block_store_wipe(
+ const char *filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SEMIHOSTING_BLOCK_STORE_H */
diff --git a/components/service/block_storage/block_store/device/semihosting/test/component.cmake b/components/service/block_storage/block_store/device/semihosting/test/component.cmake
new file mode 100644
index 000000000..a92cbacce
--- /dev/null
+++ b/components/service/block_storage/block_store/device/semihosting/test/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/sh_block_store_tests.c"
+ )
+
diff --git a/components/service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.c b/components/service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.c
new file mode 100644
index 000000000..11040d8fb
--- /dev/null
+++ b/components/service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common/uuid/uuid.h"
+#include <service/test_runner/provider/backend/simple_c/simple_c_test_runner.h>
+#include <service/block_storage/block_store/device/semihosting/semihosting_block_store.h>
+
+#define BLOCK_SIZE (128)
+#define NUM_BLOCKS (20)
+#define CLIENT_ID (0)
+
+/**
+ * Tests for the semihosting block store.
+ */
+static const char *sh_filename = "test-store.img";
+static struct semihosting_block_store sh_block_store;
+static storage_partition_handle_t partition_handle;
+
+static bool setup(struct test_failure *failure)
+{
+ semihosting_block_store_wipe(sh_filename);
+
+ if (!semihosting_block_store_init(&sh_block_store, sh_filename, BLOCK_SIZE)) {
+
+ /* Failed to initialize block store */
+ failure->line_num = __LINE__;
+ return false;
+ }
+
+ struct uuid_octets disk_guid;
+ uuid_guid_octets_from_canonical(&disk_guid,
+ "418edc38-fa66-4871-979b-e67bee88b8f2");
+
+ semihosting_block_store_configure(&sh_block_store,
+ &disk_guid,
+ NUM_BLOCKS, BLOCK_SIZE);
+
+ psa_status_t status = block_store_open(
+ &sh_block_store.base_block_device.base_block_store,
+ CLIENT_ID,
+ &disk_guid,
+ &partition_handle);
+
+ if (status != PSA_SUCCESS) {
+
+ failure->line_num = __LINE__;
+ failure->info = status;
+
+ semihosting_block_store_deinit(&sh_block_store);
+
+ return false;
+ }
+
+ return true;
+}
+
+static void teardown(void)
+{
+ block_store_close(
+ &sh_block_store.base_block_device.base_block_store,
+ CLIENT_ID,
+ partition_handle);
+
+ semihosting_block_store_deinit(&sh_block_store);
+}
+
+static bool set_block(struct test_failure *failure,
+ size_t lba, size_t offset,
+ size_t len, uint8_t val,
+ size_t *num_written)
+{
+ bool success = true;
+ struct block_store *bs = &sh_block_store.base_block_device.base_block_store;
+ uint8_t *write_buf = malloc(len);
+
+ if (!write_buf) {
+
+ failure->line_num = __LINE__;
+ return false;
+ }
+
+ memset(write_buf, val, len);
+ *num_written = 0;
+
+ psa_status_t status = block_store_write(
+ bs, CLIENT_ID, partition_handle,
+ lba, offset,
+ write_buf, len, num_written);
+
+ if (status != PSA_SUCCESS) {
+
+ failure->line_num = __LINE__;
+ failure->info = status;
+ success = false;
+ }
+
+ free(write_buf);
+
+ return success;
+}
+
+static bool check_block(struct test_failure *failure,
+ size_t lba, size_t offset,
+ size_t len, uint8_t expected_val)
+{
+ bool success = true;
+ struct block_store *bs = &sh_block_store.base_block_device.base_block_store;
+ uint8_t *read_buf = malloc(len);
+
+ if (!read_buf) {
+
+ failure->line_num = __LINE__;
+ return false;
+ }
+
+ size_t num_read = 0;
+
+ psa_status_t status = block_store_read(
+ bs, CLIENT_ID, partition_handle,
+ lba, offset,
+ len, read_buf,
+ &num_read);
+
+ if (status == PSA_SUCCESS) {
+
+ if (num_read == len) {
+
+ for (size_t i = 0; i < len; i++) {
+
+ if (read_buf[i] != expected_val) {
+
+ failure->line_num = __LINE__;
+ failure->info = read_buf[i];
+ success = false;
+ break;
+ }
+ }
+ }
+ else {
+
+ failure->line_num = __LINE__;
+ failure->info = num_read;
+ success = false;
+ }
+ }
+ else {
+
+ failure->line_num = __LINE__;
+ failure->info = status;
+ success = false;
+ }
+
+ free(read_buf);
+
+ return success;
+}
+
+static bool erase_blocks(struct test_failure *failure,
+ uint64_t begin_lba,
+ size_t num_blocks)
+{
+ bool success = true;
+ struct block_store *bs = &sh_block_store.base_block_device.base_block_store;
+
+ psa_status_t status = block_store_erase(
+ bs, CLIENT_ID, partition_handle,
+ begin_lba, num_blocks);
+
+ if (status != PSA_SUCCESS) {
+
+ failure->line_num = __LINE__;
+ failure->info = status;
+ success = false;
+ }
+
+ return success;
+}
+
+/*
+ * Check a sequence of whole block writes and reads.
+ */
+static bool check_whole_block_rw(struct test_failure *failure)
+{
+ bool pass = setup(failure);
+
+ if (pass) {
+
+ size_t num_written = 0;
+
+ if (pass && (pass = set_block(failure, 7, 0, BLOCK_SIZE, 'a', &num_written))) {
+
+ if (!(pass = (num_written == BLOCK_SIZE))) {
+
+ failure->line_num = __LINE__;
+ failure->info = num_written;
+ }
+ }
+
+ if (pass && (pass = set_block(failure, 6, 0, BLOCK_SIZE, 'b', &num_written))) {
+
+ if (!(pass = (num_written == BLOCK_SIZE))) {
+
+ failure->line_num = __LINE__;
+ failure->info = num_written;
+ }
+ }
+
+ if (pass && (pass = set_block(failure, 1, 0, BLOCK_SIZE, 'c', &num_written))) {
+
+ if (!(pass = (num_written == BLOCK_SIZE))) {
+
+ failure->line_num = __LINE__;
+ failure->info = num_written;
+ }
+ }
+
+ if (pass && (pass = set_block(failure, 9, 0, BLOCK_SIZE, 'd', &num_written))) {
+
+ if (!(pass = (num_written == BLOCK_SIZE))) {
+
+ failure->line_num = __LINE__;
+ failure->info = num_written;
+ }
+ }
+
+ /* Check written blocks are as expected */
+ if (pass) {
+
+ pass =
+ check_block(failure, 7, 0, BLOCK_SIZE, 'a') &&
+ check_block(failure, 6, 0, BLOCK_SIZE, 'b') &&
+ check_block(failure, 1, 0, BLOCK_SIZE, 'c') &&
+ check_block(failure, 9, 0, BLOCK_SIZE, 'd');
+ }
+
+ /* Erase all the written blocks */
+ if (pass) {
+
+ pass =
+ erase_blocks(failure, 9, 1) &&
+ erase_blocks(failure, 1, 1) &&
+ erase_blocks(failure, 7, 1) &&
+ erase_blocks(failure, 6, 1);
+ }
+
+ teardown();
+ }
+
+ return pass;
+}
+
+/**
+ * Define and register test group
+ */
+void sh_block_store_tests_register(void)
+{
+ static const struct simple_c_test_case sh_block_store_tests[] = {
+ {.name = "WholeBlockRw", .test_func = check_whole_block_rw},
+ };
+
+ static const struct simple_c_test_group sh_block_store_test_group =
+ {
+ .group = "ShBlockStoreTests",
+ .num_test_cases = sizeof(sh_block_store_tests)/sizeof(struct simple_c_test_case),
+ .test_cases = sh_block_store_tests
+ };
+
+ simple_c_test_runner_register_group(&sh_block_store_test_group);
+}
diff --git a/components/service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.h b/components/service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.h
new file mode 100644
index 000000000..8780647d8
--- /dev/null
+++ b/components/service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SH_BLOCK_STORE_TESTS_H
+#define SH_BLOCK_STORE_TESTS_H
+
+void sh_block_store_tests_register(void);
+
+#endif /* SH_BLOCK_STORE_TESTS_H */
diff --git a/components/service/block_storage/block_store/partitioned/component.cmake b/components/service/block_storage/block_store/partitioned/component.cmake
new file mode 100644
index 000000000..0eb6a73c9
--- /dev/null
+++ b/components/service/block_storage/block_store/partitioned/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/partitioned_block_store.c"
+ )
diff --git a/components/service/block_storage/block_store/partitioned/partitioned_block_store.c b/components/service/block_storage/block_store/partitioned/partitioned_block_store.c
new file mode 100644
index 000000000..2b72d2a3b
--- /dev/null
+++ b/components/service/block_storage/block_store/partitioned/partitioned_block_store.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include "partitioned_block_store.h"
+
+static psa_status_t find_by_partition_guid(
+ struct partitioned_block_store *partitioned_block_store,
+ const struct uuid_octets *partition_guid,
+ size_t *index)
+{
+ psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+ bool try_again = false;
+
+ do {
+
+ for (size_t i = 0; i < partitioned_block_store->num_partitions; i++) {
+
+ if (storage_partition_is_guid_matched(
+ &partitioned_block_store->storage_partition[i],
+ partition_guid)) {
+
+ *index = i;
+ status = PSA_SUCCESS;
+ break;
+ }
+ }
+
+ /* Search again if on-demand configuration was performed */
+ try_again =
+ (status != PSA_SUCCESS) &&
+ !try_again &&
+ partitioned_block_store->config_listener &&
+ partitioned_block_store->config_listener(
+ partitioned_block_store,
+ partition_guid,
+ &partitioned_block_store->back_store_info);
+
+ } while (try_again);
+
+ return status;
+}
+
+static psa_status_t validate_partition_request(
+ const struct partitioned_block_store *partitioned_block_store,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ const struct storage_partition **partition)
+{
+ size_t index = (size_t)handle;
+
+ if (index >= PARTITIONED_BLOCK_STORE_MAX_PARTITIONS)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ const struct storage_partition *requested_partition =
+ &partitioned_block_store->storage_partition[index];
+
+ if (!storage_partition_is_access_permitted(requested_partition, client_id))
+ return PSA_ERROR_NOT_PERMITTED;
+
+ /* Access permitted to requested partition */
+ *partition = requested_partition;
+
+ return PSA_SUCCESS;
+}
+
+static psa_status_t partitioned_block_store_get_partition_info(void *context,
+ const struct uuid_octets *partition_guid,
+ struct storage_partition_info *info)
+{
+ struct partitioned_block_store *partitioned_block_store =
+ (struct partitioned_block_store*)context;
+
+ size_t partition_index = 0;
+ psa_status_t status = find_by_partition_guid(
+ partitioned_block_store,
+ partition_guid,
+ &partition_index);
+
+ if (status == PSA_SUCCESS) {
+
+ const struct storage_partition *partition =
+ &partitioned_block_store->storage_partition[partition_index];
+
+ info->block_size = partition->block_size;
+ info->num_blocks = partition->num_blocks;
+ info->partition_guid = partition->partition_guid;
+ info->parent_guid = partitioned_block_store->back_store_info.partition_guid;
+ }
+
+ return status;
+}
+
+static psa_status_t partitioned_block_store_open(void *context,
+ uint32_t client_id,
+ const struct uuid_octets *partition_guid,
+ storage_partition_handle_t *handle)
+{
+ struct partitioned_block_store *partitioned_block_store =
+ (struct partitioned_block_store*)context;
+
+ size_t partition_index = 0;
+ psa_status_t status = find_by_partition_guid(
+ partitioned_block_store,
+ partition_guid,
+ &partition_index);
+
+ if (status == PSA_SUCCESS) {
+
+ struct storage_partition *partition =
+ &partitioned_block_store->storage_partition[partition_index];
+
+ if (storage_partition_is_open_permitted(partition,
+ client_id,
+ partitioned_block_store->authorizer)) {
+
+ *handle = (storage_partition_handle_t)partition_index;
+ }
+ else {
+
+ status = PSA_ERROR_NOT_PERMITTED;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t partitioned_block_store_close(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle)
+{
+ const struct partitioned_block_store *partitioned_block_store =
+ (struct partitioned_block_store*)context;
+
+ const struct storage_partition *partition = NULL;
+
+ psa_status_t status = validate_partition_request(
+ partitioned_block_store,
+ client_id,
+ handle,
+ &partition);
+
+ return status;
+}
+
+static psa_status_t partitioned_block_store_read(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ size_t buffer_size,
+ uint8_t *buffer,
+ size_t *data_len)
+{
+ const struct partitioned_block_store *partitioned_block_store =
+ (struct partitioned_block_store*)context;
+
+ const struct storage_partition *partition = NULL;
+
+ psa_status_t status = validate_partition_request(
+ partitioned_block_store,
+ client_id,
+ handle,
+ &partition);
+
+ if (status == PSA_SUCCESS) {
+
+ if (storage_partition_is_lba_legal(partition, lba)) {
+
+ size_t clipped_read_len = storage_partition_clip_length(
+ partition,
+ lba, offset,
+ buffer_size);
+
+ /* Read from underlying back store */
+ status = block_store_read(
+ partitioned_block_store->back_store,
+ partitioned_block_store->local_client_id,
+ partitioned_block_store->back_store_handle,
+ partition->base_lba + lba,
+ offset,
+ clipped_read_len,
+ buffer,
+ data_len);
+ }
+ else {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t partitioned_block_store_write(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t lba,
+ size_t offset,
+ const uint8_t *data,
+ size_t data_len,
+ size_t *num_written)
+{
+ const struct partitioned_block_store *partitioned_block_store =
+ (struct partitioned_block_store*)context;
+
+ const struct storage_partition *partition = NULL;
+
+ psa_status_t status = validate_partition_request(
+ partitioned_block_store,
+ client_id,
+ handle,
+ &partition);
+
+ if (status == PSA_SUCCESS) {
+
+ if (storage_partition_is_lba_legal(partition, lba)) {
+
+ size_t clipped_data_len = storage_partition_clip_length(
+ partition, lba, offset,
+ data_len);
+
+ /* Write to underlying back store */
+ status = block_store_write(
+ partitioned_block_store->back_store,
+ partitioned_block_store->local_client_id,
+ partitioned_block_store->back_store_handle,
+ partition->base_lba + lba,
+ offset,
+ data,
+ clipped_data_len,
+ num_written);
+ }
+ else {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+static psa_status_t partitioned_block_store_erase(void *context,
+ uint32_t client_id,
+ storage_partition_handle_t handle,
+ uint64_t begin_lba,
+ size_t num_blocks)
+{
+ const struct partitioned_block_store *partitioned_block_store =
+ (struct partitioned_block_store*)context;
+
+ const struct storage_partition *partition = NULL;
+
+ psa_status_t status = validate_partition_request(
+ partitioned_block_store,
+ client_id,
+ handle,
+ &partition);
+
+ if (status == PSA_SUCCESS) {
+
+ if (storage_partition_is_lba_legal(partition, begin_lba)) {
+
+ size_t clipped_num_blocks = storage_partition_clip_num_blocks(
+ partition, begin_lba,
+ num_blocks);
+
+ status = block_store_erase(
+ partitioned_block_store->back_store,
+ partitioned_block_store->local_client_id,
+ partitioned_block_store->back_store_handle,
+ partition->base_lba + begin_lba,
+ clipped_num_blocks);
+ }
+ else {
+
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+struct block_store *partitioned_block_store_init(
+ struct partitioned_block_store *partitioned_block_store,
+ uint32_t local_client_id,
+ const struct uuid_octets *back_store_guid,
+ struct block_store *back_store,
+ storage_partition_authorizer authorizer)
+{
+ /* Define concrete block store interface */
+ static const struct block_store_interface interface =
+ {
+ partitioned_block_store_get_partition_info,
+ partitioned_block_store_open,
+ partitioned_block_store_close,
+ partitioned_block_store_read,
+ partitioned_block_store_write,
+ partitioned_block_store_erase
+ };
+
+ /* Initialize base block_store */
+ partitioned_block_store->base_block_store.context = partitioned_block_store;
+ partitioned_block_store->base_block_store.interface = &interface;
+
+ /* Note the local client ID - this corresponds to the local environment */
+ partitioned_block_store->local_client_id = local_client_id;
+
+ /* Note the environment specific authorizer function */
+ partitioned_block_store->authorizer = authorizer;
+
+ /* Default to no config listener */
+ partitioned_block_store->config_listener = NULL;
+
+ /* Initially no partitions. */
+ partitioned_block_store->num_partitions = 0;
+
+ /* Stack over provided back store */
+ partitioned_block_store->back_store = back_store;
+
+ /* Get information about the underlying back store */
+ struct storage_partition_info info;
+ psa_status_t status = block_store_get_partition_info(partitioned_block_store->back_store,
+ back_store_guid,
+ &info);
+
+ if (status != PSA_SUCCESS)
+ return NULL;
+
+ partitioned_block_store->back_store_info = info;
+
+ /* Open underlying block store */
+ status = block_store_open(partitioned_block_store->back_store,
+ partitioned_block_store->local_client_id,
+ back_store_guid,
+ &partitioned_block_store->back_store_handle);
+
+ if (status != PSA_SUCCESS)
+ return NULL;
+
+ return &partitioned_block_store->base_block_store;
+}
+
+void partitioned_block_store_deinit(
+ struct partitioned_block_store *partitioned_block_store)
+{
+ block_store_close(partitioned_block_store->back_store,
+ partitioned_block_store->local_client_id,
+ partitioned_block_store->back_store_handle);
+
+ for (size_t i = 0; i < partitioned_block_store->num_partitions; ++i)
+ storage_partition_deinit(&partitioned_block_store->storage_partition[i]);
+}
+
+void partitioned_block_store_attach_config_listener(
+ struct partitioned_block_store *partitioned_block_store,
+ partition_config_listener config_listener)
+{
+ partitioned_block_store->config_listener = config_listener;
+}
+
+bool partitioned_block_store_add_partition(
+ struct partitioned_block_store *partitioned_block_store,
+ const struct uuid_octets *partition_guid,
+ uint64_t starting_lba,
+ uint64_t ending_lba,
+ uint64_t attributes,
+ const char *owner)
+{
+ (void)attributes;
+ (void)owner;
+
+ if (partitioned_block_store->num_partitions >= PARTITIONED_BLOCK_STORE_MAX_PARTITIONS)
+ return false;
+
+ /* Check partition blocks lie within limits of the back store */
+ if ((starting_lba > ending_lba) ||
+ (ending_lba >= partitioned_block_store->back_store_info.num_blocks))
+ return false;
+
+ /* Initialise a new storage_partition structure */
+ struct storage_partition *storage_partition =
+ &partitioned_block_store->storage_partition[partitioned_block_store->num_partitions];
+
+ storage_partition_init(
+ storage_partition,
+ partition_guid,
+ ending_lba - starting_lba + 1,
+ partitioned_block_store->back_store_info.block_size);
+
+ storage_partition->base_lba = starting_lba;
+
+ ++partitioned_block_store->num_partitions;
+
+ return true;
+}
+
+const struct storage_partition_info *partitioned_block_store_get_back_store_info(
+ const struct partitioned_block_store *partitioned_block_store)
+{
+ return &partitioned_block_store->back_store_info;
+}
diff --git a/components/service/block_storage/block_store/partitioned/partitioned_block_store.h b/components/service/block_storage/block_store/partitioned/partitioned_block_store.h
new file mode 100644
index 000000000..bcd0b50af
--- /dev/null
+++ b/components/service/block_storage/block_store/partitioned/partitioned_block_store.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PARTITIONED_BLOCK_STORE_H
+#define PARTITIONED_BLOCK_STORE_H
+
+#include <stdbool.h>
+#include "service/block_storage/block_store/block_store.h"
+#include "service/block_storage/block_store/storage_partition.h"
+#include "service/block_storage/block_store/storage_partition_acl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef PARTITIONED_BLOCK_STORE_MAX_PARTITIONS
+#define PARTITIONED_BLOCK_STORE_MAX_PARTITIONS (8)
+#endif
+
+/* Forward declaration */
+struct partitioned_block_store;
+
+/**
+ * \brief partition configuration listener
+ *
+ * A callback for implementing on-demand partition configuration for cases when
+ * there is a request to open a partition but the requested partition has not
+ * yet been configured. Attaching a partition configuration listener is optional.
+ *
+ * \param[in] partitioned_block_store The subject partitioned_block_store
+ * \param[in] partition_guid The requested partition GUID
+ * \param[in] back_store_info Information about the back store
+ *
+ * \return Return true if configuration successful
+ */
+typedef bool (*partition_config_listener)(
+ struct partitioned_block_store *partitioned_block_store,
+ const struct uuid_octets *partition_guid,
+ const struct storage_partition_info *back_store_info);
+
+/**
+ * \brief partitioned_block_store structure
+ *
+ * A partitioned_block_store is a stackable block_store that enables an underlying
+ * block store to be presented as a set of independent storage partitions, each identified
+ * by its own GUID. Storage partition attributes will have been defined by platform
+ * configuration data e.g. read from a GPT. The method for obtaining partition configuration
+ * is outside of the scope of the partitioned_block_store.
+ */
+struct partitioned_block_store
+{
+ struct block_store base_block_store;
+ uint32_t local_client_id;
+ storage_partition_authorizer authorizer;
+ partition_config_listener config_listener;
+ size_t num_partitions;
+ struct storage_partition storage_partition[PARTITIONED_BLOCK_STORE_MAX_PARTITIONS];
+ storage_partition_handle_t back_store_handle;
+ struct block_store *back_store;
+ struct storage_partition_info back_store_info;
+};
+
+/**
+ * \brief Initialize a partitioned_block_store
+ *
+ * After initialization, no storage partitions are defined. Partitions must be added,
+ * one a time, by calling partitioned_block_store_add_partition.
+ *
+ * \param[in] partitioned_block_store The subject partitioned_block_store
+ * \param[in] local_client_id Client ID corresponding to the current environment
+ * \param[in] back_store_guid The partition GUID to use in the underlying back store
+ * \param[in] back_store The associated back store
+ * \param[in] authorizer Optional authorizer function for authorizing clients
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *partitioned_block_store_init(
+ struct partitioned_block_store *partitioned_block_store,
+ uint32_t local_client_id,
+ const struct uuid_octets *back_store_guid,
+ struct block_store *back_store,
+ storage_partition_authorizer authorizer);
+
+/**
+ * \brief De-initialize a partitioned_block_store
+ *
+ * Frees resource allocated during call to partitioned_block_store_init().
+ *
+ * \param[in] partitioned_block_store The subject partitioned_block_store
+ */
+void partitioned_block_store_deinit(
+ struct partitioned_block_store *partitioned_block_store);
+
+/**
+ * \brief Attach a config listener
+ *
+ * Allows an on-demand partition configurator to receive a callback when an
+ * attempt is made to open a partition that has not been configured.
+ *
+ * \param[in] partitioned_block_store The subject partitioned_block_store
+ * \param[in] config_listener Optional on-demand configurator
+ */
+void partitioned_block_store_attach_config_listener(
+ struct partitioned_block_store *partitioned_block_store,
+ partition_config_listener config_listener);
+
+/**
+ * \brief Add a storage partition
+ *
+ * Called for each partition defined in platform configuration. Parameters
+ * correspond to partition parameters defined in the UEFI specification for
+ * GUID Partition Tables (GPT).
+ *
+ * \param[in] partitioned_block_store The subject partitioned_block_store
+ * \param[in] partition_guid The unique partition GUID
+ * \param[in] starting_lba The back store lba that corresponds to the partition start
+ * \param[in] ending_lba The back store lba that corresponds to the final block in the partition
+ * \param[in] attributes Partition attributes bitmap
+ * \param[in] owner Partition owner ID string
+ *
+ * \return True if successful
+ */
+bool partitioned_block_store_add_partition(
+ struct partitioned_block_store *partitioned_block_store,
+ const struct uuid_octets *partition_guid,
+ uint64_t starting_lba,
+ uint64_t ending_lba,
+ uint64_t attributes,
+ const char *owner);
+
+/**
+ * \brief Get information about back store
+ *
+ * Returns information about the underlying block device that is being partitioned
+ *
+ * \param[in] partitioned_block_store The subject partitioned_block_store
+ *
+ * \return Pointer to storage_partition_info structure.
+ */
+const struct storage_partition_info *partitioned_block_store_get_back_store_info(
+ const struct partitioned_block_store *partitioned_block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PARTITIONED_BLOCK_STORE_H */
diff --git a/components/service/block_storage/block_store/partitioned/test/component.cmake b/components/service/block_storage/block_store/partitioned/test/component.cmake
new file mode 100644
index 000000000..7e55d6fa2
--- /dev/null
+++ b/components/service/block_storage/block_store/partitioned/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/partitioned_block_store_tests.cpp"
+ )
diff --git a/components/service/block_storage/block_store/partitioned/test/partitioned_block_store_tests.cpp b/components/service/block_storage/block_store/partitioned/test/partitioned_block_store_tests.cpp
new file mode 100644
index 000000000..560db2967
--- /dev/null
+++ b/components/service/block_storage/block_store/partitioned/test/partitioned_block_store_tests.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstring>
+#include "common/uuid/uuid.h"
+#include "service/block_storage/block_store/device/ram/ram_block_store.h"
+#include "service/block_storage/block_store/partitioned/partitioned_block_store.h"
+#include "CppUTest/TestHarness.h"
+
+TEST_GROUP(PartitionedBlockStoreTests)
+{
+ void setup()
+ {
+ /* Initialize a ram_block_store to use as the back store */
+ uuid_guid_octets_from_canonical(&m_back_store_guid,
+ "6ec10ff6-4252-4ef7-aeca-5036db6697df");
+
+ struct block_store *back_store = ram_block_store_init(
+ &m_ram_store,
+ &m_back_store_guid,
+ BACK_STORE_NUM_BLOCKS,
+ BACK_STORE_BLOCK_SIZE);
+
+ CHECK_TRUE(back_store);
+
+ /* Stack a partitioned_block_store over the back store */
+ m_block_store = partitioned_block_store_init(
+ &m_partitioned_store,
+ LOCAL_CLIENT_ID,
+ &m_back_store_guid,
+ back_store,
+ NULL);
+
+ CHECK_TRUE(back_store);
+
+ /* Configure partition 1 */
+ uuid_guid_octets_from_canonical(&m_partition_1_guid,
+ "18ae7d62-0974-4dd3-8d2e-e9c166554165");
+
+ CHECK_TRUE(partitioned_block_store_add_partition(
+ &m_partitioned_store,
+ &m_partition_1_guid,
+ PARTITION_1_STARTING_LBA,
+ PARTITION_1_ENDING_LBA,
+ 0, NULL));
+
+ /* Configure partition 2 */
+ uuid_guid_octets_from_canonical(&m_partition_2_guid,
+ "7924fda7-4666-41d7-887a-91a913712b93");
+
+ CHECK_TRUE(partitioned_block_store_add_partition(
+ &m_partitioned_store,
+ &m_partition_2_guid,
+ PARTITION_2_STARTING_LBA,
+ PARTITION_2_ENDING_LBA,
+ 0, NULL));
+ }
+
+ void teardown()
+ {
+ ram_block_store_deinit(&m_ram_store);
+ partitioned_block_store_deinit(&m_partitioned_store);
+ }
+
+ /* Back store configuration */
+ static const size_t BACK_STORE_NUM_BLOCKS = 100;
+ static const size_t BACK_STORE_BLOCK_SIZE = 512;
+
+ /* Partition 1 configuration */
+ static const size_t PARTITION_1_STARTING_LBA = 5;
+ static const size_t PARTITION_1_ENDING_LBA = 49;
+
+ /* Partition 2 configuration */
+ static const size_t PARTITION_2_STARTING_LBA = 60;
+ static const size_t PARTITION_2_ENDING_LBA = 99;
+
+ static const uint32_t LOCAL_CLIENT_ID = 11;
+
+ struct block_store *m_block_store;
+ struct ram_block_store m_ram_store;
+ struct partitioned_block_store m_partitioned_store;
+ struct uuid_octets m_partition_1_guid;
+ struct uuid_octets m_partition_2_guid;
+ struct uuid_octets m_back_store_guid;
+};
+
+TEST(PartitionedBlockStoreTests, getPartitionInfo)
+{
+ struct storage_partition_info info;
+
+ /* Check partition info for partition 1 */
+ psa_status_t status = block_store_get_partition_info(
+ m_block_store, &m_partition_1_guid, &info);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ LONGS_EQUAL(PARTITION_1_ENDING_LBA - PARTITION_1_STARTING_LBA + 1, info.num_blocks);
+ LONGS_EQUAL(BACK_STORE_BLOCK_SIZE, info.block_size);
+ MEMCMP_EQUAL(m_partition_1_guid.octets,
+ info.partition_guid.octets, sizeof(info.partition_guid.octets));
+ MEMCMP_EQUAL(m_back_store_guid.octets,
+ info.parent_guid.octets, sizeof(info.parent_guid.octets));
+
+ /* Check partition info for partition 2 */
+ status = block_store_get_partition_info(
+ m_block_store, &m_partition_2_guid, &info);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ LONGS_EQUAL(PARTITION_2_ENDING_LBA - PARTITION_2_STARTING_LBA + 1, info.num_blocks);
+ LONGS_EQUAL(BACK_STORE_BLOCK_SIZE, info.block_size);
+ MEMCMP_EQUAL(m_partition_2_guid.octets,
+ info.partition_guid.octets, sizeof(info.partition_guid.octets));
+ MEMCMP_EQUAL(m_back_store_guid.octets,
+ info.parent_guid.octets, sizeof(info.parent_guid.octets));
+}
+
+TEST(PartitionedBlockStoreTests, openClose)
+{
+ storage_partition_handle_t handle_1;
+ storage_partition_handle_t handle_2;
+
+ psa_status_t status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_1_guid, &handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_1_guid, &handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
+
+TEST(PartitionedBlockStoreTests, writeReadEraseBlock)
+{
+ storage_partition_handle_t handle_1;
+ storage_partition_handle_t handle_2;
+ uint8_t write_buffer[BACK_STORE_BLOCK_SIZE];
+ uint8_t read_buffer[BACK_STORE_BLOCK_SIZE];
+ size_t data_len = 0;
+ size_t num_written = 0;
+ uint64_t lba_1 = 10;
+ uint64_t lba_2 = 7;
+
+ /* Open sessions associated with both partitions */
+ psa_status_t status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_1_guid, &handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_2_guid, &handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Write different data to both partitions - expect both to work */
+ memset(write_buffer, 0xaa, sizeof(write_buffer));
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_1, lba_1,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), num_written);
+
+ memset(write_buffer, 0xbb, sizeof(write_buffer));
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_2, lba_2,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), num_written);
+
+ /* Expect to read back the same data from both partitions*/
+ memset(write_buffer, 0xaa, sizeof(write_buffer));
+ memset(read_buffer, 0, sizeof(read_buffer));
+ status = block_store_read(
+ m_block_store, LOCAL_CLIENT_ID, handle_1, lba_1, 0,
+ sizeof(read_buffer), read_buffer, &data_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), data_len);
+ MEMCMP_EQUAL(write_buffer, read_buffer, sizeof(write_buffer));
+
+ memset(write_buffer, 0xbb, sizeof(write_buffer));
+ memset(read_buffer, 0, sizeof(read_buffer));
+ status = block_store_read(
+ m_block_store, LOCAL_CLIENT_ID, handle_2, lba_2,
+ 0, sizeof(read_buffer), read_buffer, &data_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), data_len);
+ MEMCMP_EQUAL(write_buffer, read_buffer, sizeof(write_buffer));
+
+ /* Erase the block in the partition 1 */
+ status = block_store_erase(m_block_store, LOCAL_CLIENT_ID, handle_1, lba_1, 1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Write to an erased block in partition 1 should work as block was erase */
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_1, lba_1,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), num_written);
+
+ /* Write to the previously written block in partition 2 should fail as it hasn't been erased */
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_2, lba_2,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, status);
+
+ /* Erase the block in the partition 2 */
+ status = block_store_erase(m_block_store, LOCAL_CLIENT_ID, handle_2, lba_2, 1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Now the write to partition 2 should work */
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_2, lba_2,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), num_written);
+
+ /* Expect to successfully close both sessions */
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
+
+TEST(PartitionedBlockStoreTests, checkEraseLimits)
+{
+ storage_partition_handle_t handle_1;
+ storage_partition_handle_t handle_2;
+ uint8_t write_buffer[BACK_STORE_BLOCK_SIZE];
+ uint8_t read_buffer[BACK_STORE_BLOCK_SIZE];
+ size_t data_len = 0;
+ size_t num_written = 0;
+
+ /* Open sessions associated with both partitions */
+ psa_status_t status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_1_guid, &handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_2_guid, &handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Write same data to the beginning of both partitions */
+ memset(write_buffer, 0xaa, sizeof(write_buffer));
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_1, 0,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), num_written);
+
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_2, 0,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), num_written);
+
+ /* Expect to read back the same data from both partitions*/
+ memset(read_buffer, 0, sizeof(read_buffer));
+ status = block_store_read(
+ m_block_store, LOCAL_CLIENT_ID, handle_1, 0, 0,
+ sizeof(read_buffer), read_buffer, &data_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), data_len);
+ MEMCMP_EQUAL(write_buffer, read_buffer, sizeof(write_buffer));
+
+ memset(read_buffer, 0, sizeof(read_buffer));
+ status = block_store_read(
+ m_block_store, LOCAL_CLIENT_ID, handle_2, 0,
+ 0, sizeof(read_buffer), read_buffer, &data_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), data_len);
+ MEMCMP_EQUAL(write_buffer, read_buffer, sizeof(write_buffer));
+
+ /* Erase partition 1 with a block count that exceeds the limits of the partition */
+ status = block_store_erase(m_block_store, LOCAL_CLIENT_ID, handle_1, 0, 60);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Still expect data in partition 2 to be intact */
+ memset(read_buffer, 0, sizeof(read_buffer));
+ status = block_store_read(
+ m_block_store, LOCAL_CLIENT_ID, handle_2, 0,
+ 0, sizeof(read_buffer), read_buffer, &data_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), data_len);
+ MEMCMP_EQUAL(write_buffer, read_buffer, sizeof(write_buffer));
+
+ /* Expect to successfully close both sessions */
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
+
+
+TEST(PartitionedBlockStoreTests, writeToInvalidBlock)
+{
+ storage_partition_handle_t handle_1;
+ storage_partition_handle_t handle_2;
+ uint8_t write_buffer[BACK_STORE_BLOCK_SIZE];
+ size_t num_written = 0;
+ struct storage_partition_info info_1;
+ struct storage_partition_info info_2;
+
+ /* Choose LBAs that lie outside of limits of partitions */
+ psa_status_t status = block_store_get_partition_info(
+ m_block_store, &m_partition_1_guid, &info_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_get_partition_info(
+ m_block_store, &m_partition_2_guid, &info_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ uint64_t lba_1 = info_1.num_blocks;
+ uint64_t lba_2 = info_2.num_blocks + 1000;
+
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_1_guid, &handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_2_guid, &handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Write to block beyond the limits of the storage partition should fail */
+ memset(write_buffer, 0xaa, sizeof(write_buffer));
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_1, lba_1,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle_2, lba_2,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+
+ /* Close the sessions */
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
diff --git a/components/service/block_storage/block_store/storage_partition.c b/components/service/block_storage/block_store/storage_partition.c
new file mode 100644
index 000000000..af982095e
--- /dev/null
+++ b/components/service/block_storage/block_store/storage_partition.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+#include "storage_partition.h"
+
+
+void storage_partition_init(
+ struct storage_partition *partition,
+ const struct uuid_octets *partition_guid,
+ size_t num_blocks,
+ size_t block_size)
+{
+ memset(partition, 0, sizeof(struct storage_partition));
+
+ if (partition_guid) partition->partition_guid = *partition_guid;
+ partition->block_size = block_size;
+ partition->num_blocks = num_blocks;
+
+ partition->base_lba = 0;
+ storage_partition_acl_init(&partition->acl);
+}
+
+void storage_partition_deinit(
+ struct storage_partition *partition)
+{
+ memset(partition, 0, sizeof(struct storage_partition));
+}
+
+bool storage_partition_grant_access(
+ struct storage_partition *partition,
+ uint32_t client_id)
+{
+ return storage_partition_acl_add(&partition->acl, client_id);
+}
+
+bool storage_partition_assign_ownership(
+ struct storage_partition *partition,
+ const char *owner_id)
+{
+ return storage_partition_acl_set_owner_id(&partition->acl, owner_id);
+}
+
+bool storage_partition_is_guid_matched(
+ const struct storage_partition *partition,
+ const struct uuid_octets *partition_guid)
+{
+ return (memcmp(&partition->partition_guid, partition_guid, sizeof(struct uuid_octets)) == 0);
+}
+
+bool storage_partition_is_open_permitted(
+ struct storage_partition *partition,
+ uint32_t client_id,
+ storage_partition_authorizer authorizer)
+{
+ return storage_partition_acl_authorize(&partition->acl, client_id, authorizer);
+}
+
+bool storage_partition_is_access_permitted(
+ const struct storage_partition *partition,
+ uint32_t client_id)
+{
+ return storage_partition_acl_check(&partition->acl, client_id);
+}
+
+bool storage_partition_is_lba_legal(
+ const struct storage_partition *partition,
+ uint64_t lba)
+{
+ return lba < partition->num_blocks;
+}
+
+size_t storage_partition_clip_length(
+ const struct storage_partition *partition,
+ uint64_t lba,
+ size_t offset,
+ size_t req_len)
+{
+ size_t clipped_len = 0;
+
+ if (lba < partition->num_blocks) {
+
+ size_t remaining_len = (partition->num_blocks - lba) * partition->block_size;
+
+ remaining_len = (offset < remaining_len) ? remaining_len - offset : 0;
+ clipped_len = (req_len > remaining_len) ? remaining_len : req_len;
+ }
+
+ return clipped_len;
+}
+
+size_t storage_partition_clip_num_blocks(
+ const struct storage_partition *partition,
+ uint64_t lba,
+ size_t num_blocks)
+{
+ size_t clipped_num_blocks = 0;
+
+ if (lba < partition->num_blocks) {
+
+ size_t remaining_blocks = partition->num_blocks - lba;
+
+ clipped_num_blocks = (num_blocks > remaining_blocks) ? remaining_blocks : num_blocks;
+ }
+
+ return clipped_num_blocks;
+}
diff --git a/components/service/block_storage/block_store/storage_partition.h b/components/service/block_storage/block_store/storage_partition.h
new file mode 100644
index 000000000..98bd045cd
--- /dev/null
+++ b/components/service/block_storage/block_store/storage_partition.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef STORAGE_PARTITION_H
+#define STORAGE_PARTITION_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include "common/uuid/uuid.h"
+#include "storage_partition_acl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Common storage partition structure
+ *
+ * A block store may present one or more storage partitions. This structure may
+ * be used by concrete block_store implementations to describe a storage partition
+ * in a generic way.
+ */
+struct storage_partition
+{
+ /* Unique partition GUID */
+ struct uuid_octets partition_guid;
+
+ /* Block size in bytes */
+ size_t block_size;
+
+ /* The number of contiguous blocks from LBA zero */
+ size_t num_blocks;
+
+ /* Backend storage block that corresponds to LBA zero */
+ uint64_t base_lba;
+
+ /* Access control list for controlling access to configured owner */
+ struct storage_partition_acl acl;
+};
+
+/**
+ * \brief Default storage_partition initialization function
+ *
+ * Initializes a storage_partition with a one-to-one LBA mapping to backend
+ * storage and open access for any client.
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] partition_guid The unique partition GUID
+ * \param[in] num_blocks The number of contiguous blocks
+ * \param[in] block_size Block size in bytes
+ */
+void storage_partition_init(
+ struct storage_partition *partition,
+ const struct uuid_octets *partition_guid,
+ size_t num_blocks,
+ size_t block_size);
+
+/**
+ * \brief Cleans up a previously initialized storage_partition
+ *
+ * Should be called when the storage_partition is no longer needed.
+ *
+ * \param[in] partition The subject storage_partition
+ */
+void storage_partition_deinit(
+ struct storage_partition *partition);
+
+/**
+ * \brief Grant access to a specific client
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] client_id The client ID to grant access to
+ * \return True if successful
+ */
+bool storage_partition_grant_access(
+ struct storage_partition *partition,
+ uint32_t client_id);
+
+/**
+ * \brief Assign ownership using a resolvable owner ID string
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] owner_id Owner ID string
+ * \return True if successful
+ */
+bool storage_partition_assign_ownership(
+ struct storage_partition *partition,
+ const char *owner_id);
+
+/**
+ * \brief Check if unique partition GUID matches
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] partition_guid The unique partition GUID
+ * \return True if GUID matches the storage partition GUID
+ */
+bool storage_partition_is_guid_matched(
+ const struct storage_partition *partition,
+ const struct uuid_octets *partition_guid);
+
+/**
+ * \brief Perform checks on opening a partition
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] client_id The requesting client ID
+ * \param[in] authorizer Optional authorizer function
+ * \return True if access permitted
+ */
+bool storage_partition_is_open_permitted(
+ struct storage_partition *partition,
+ uint32_t client_id,
+ storage_partition_authorizer authorizer);
+
+/**
+ * \brief Check if access to the storage partition is permitted
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] client_id The requesting client ID
+ * \return True if access permitted
+ */
+bool storage_partition_is_access_permitted(
+ const struct storage_partition *partition,
+ uint32_t client_id);
+
+/**
+ * \brief Check if lba is legal for partition
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] lba The LBA to check
+ * \return True if legal
+ */
+bool storage_partition_is_lba_legal(
+ const struct storage_partition *partition,
+ uint64_t lba);
+
+/**
+ * \brief Clip the length if it exceeds the limits of the partition
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] lba The start LBA
+ * \param[in] offset Byte off set from start of block
+ * \param[in] req_len Requested length
+ * \return Clipped length if req_len exceeds limit of partition
+ */
+size_t storage_partition_clip_length(
+ const struct storage_partition *partition,
+ uint64_t lba,
+ size_t offset,
+ size_t req_len);
+
+/**
+ * \brief Clip the number of blocks if it exceeds the limits of the partition
+ *
+ * \param[in] partition The subject storage_partition
+ * \param[in] lba The start LBA
+ * \param[in] num_blocks Requested num_blocks
+ * \return Clipped num_blocks if request number exceeds the limits of the partition
+ */
+size_t storage_partition_clip_num_blocks(
+ const struct storage_partition *partition,
+ uint64_t lba,
+ size_t num_blocks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STORAGE_PARTITION_H */
diff --git a/components/service/block_storage/block_store/storage_partition_acl.c b/components/service/block_storage/block_store/storage_partition_acl.c
new file mode 100644
index 000000000..127fc2e2b
--- /dev/null
+++ b/components/service/block_storage/block_store/storage_partition_acl.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+#include "storage_partition_acl.h"
+
+void storage_partition_acl_init(
+ struct storage_partition_acl *acl)
+{
+ memset(acl, 0, sizeof(struct storage_partition_acl));
+}
+
+bool storage_partition_acl_add(
+ struct storage_partition_acl *acl,
+ uint32_t client_id)
+{
+ if (acl->allowlist_len < STORAGE_PARTITION_ACL_ALLOWLIST_LEN) {
+
+ acl->allowlist[acl->allowlist_len] = client_id;
+ ++acl->allowlist_len;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool storage_partition_acl_set_owner_id(
+ struct storage_partition_acl *acl,
+ const char *owner_id)
+{
+ size_t len = strlen(owner_id);
+
+ if (len < STORAGE_PARTITION_ACL_MAX_OWNER_ID_LEN) {
+
+ strcpy(acl->owner_id, owner_id);
+ return true;
+ }
+
+ return false;
+}
+
+bool storage_partition_acl_check(
+ const struct storage_partition_acl *acl,
+ uint32_t client_id)
+{
+ bool is_access_permitted = false;
+
+ for (size_t i = 0; !is_access_permitted && (i < acl->allowlist_len); ++i)
+ is_access_permitted = (client_id == acl->allowlist[i]);
+
+ return is_access_permitted;
+}
+
+bool storage_partition_acl_authorize(
+ struct storage_partition_acl *acl,
+ uint32_t client_id,
+ storage_partition_authorizer authorizer)
+{
+ bool is_access_permitted = storage_partition_acl_check(acl, client_id);
+
+ if (!is_access_permitted) {
+
+ /* Client ID is not currently allowlisted. Allow a deployment
+ * specific authorizer to implement its own policy or check that
+ * the present client ID resolves to the configured owner ID for
+ * the storage partition.
+ */
+ if (authorizer) {
+
+ if (authorizer(client_id, acl->owner_id))
+ is_access_permitted = storage_partition_acl_add(acl, client_id);
+ } else {
+
+ /* If no authorizer is configured, and no owner_id string has been
+ * configured, allow access to the first client to request access.
+ * This allows for an access policy where clients request access during
+ * initialization and the permission granted on the initial request
+ * persists. This policy could be suitable for secure world clients
+ * where access permission to partitions can be claimed prior to
+ * normal world boot-up.
+ */
+ if (!acl->allowlist_len && !acl->owner_id[0])
+ is_access_permitted = storage_partition_acl_add(acl, client_id);
+ }
+ }
+
+ return is_access_permitted;
+}
diff --git a/components/service/block_storage/block_store/storage_partition_acl.h b/components/service/block_storage/block_store/storage_partition_acl.h
new file mode 100644
index 000000000..d3c52196f
--- /dev/null
+++ b/components/service/block_storage/block_store/storage_partition_acl.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef STORAGE_PARTITION_ACL_H
+#define STORAGE_PARTITION_ACL_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* By default, the ACL allowlist only accommodates a single client for
+ * a storage partition. This may be overridden per deployment at build-time
+ * if multiple clients need to be supported.
+ */
+#ifndef STORAGE_PARTITION_ACL_ALLOWLIST_LEN
+#define STORAGE_PARTITION_ACL_ALLOWLIST_LEN (1)
+#endif
+
+/* Default maximum owner ID string length */
+#ifndef STORAGE_PARTITION_ACL_MAX_OWNER_ID_LEN
+#define STORAGE_PARTITION_ACL_MAX_OWNER_ID_LEN (40)
+#endif
+
+/* Forward declarations */
+struct storage_partition_acl;
+
+/**
+ * \brief Authorizer function
+ *
+ * Implements deployment specific authorization policy and owner ID
+ * resolution to determine if the presented client ID is allowed access.
+ * A concrete authorizer may perform an environment specific discovery operation
+ * to check if the presented client ID corresponds to the configured
+ * owner ID.
+ *
+ * \param[in] client_id The presented client ID
+ * \param[in] owner_id The configured owner ID
+ * \return True if client_id is permitted access
+ */
+typedef bool (*storage_partition_authorizer)(
+ uint32_t client_id,
+ const char *owner_id);
+
+/**
+ * \brief Storage partition access control list
+ *
+ * Access to a storage partition may be controlled by either adding specific
+ * client IDs to the access control list or by providing an authorizer function
+ * that will resolve the owner ID string to a set of client IDs. The authorizer
+ * allows for lazy resolution for an owner ID to client ID at the point that
+ * a client attempts to open a partition but its client ID is not present in
+ * the ACL.
+ */
+struct storage_partition_acl {
+ char owner_id[STORAGE_PARTITION_ACL_MAX_OWNER_ID_LEN];
+ size_t allowlist_len;
+ uint32_t allowlist[STORAGE_PARTITION_ACL_ALLOWLIST_LEN];
+};
+
+/**
+ * \brief Initialise an empty storage_partition_acl
+ *
+ * \param[in] acl The subject storage_partition_acl
+ */
+void storage_partition_acl_init(
+ struct storage_partition_acl *acl);
+
+/**
+ * \brief Add a client ID to the ACL allowlist
+ *
+ * \param[in] acl The subject storage_partition_acl
+ * \param[in] client_id Client ID to add
+ * \return True if added successfully
+ */
+bool storage_partition_acl_add(
+ struct storage_partition_acl *acl,
+ uint32_t client_id);
+
+/**
+ * \brief Set the owner ID string
+ *
+ * \param[in] acl The subject storage_partition_acl
+ * \param[in] owner_id Owner ID string
+ * \return True if successful
+ */
+bool storage_partition_acl_set_owner_id(
+ struct storage_partition_acl *acl,
+ const char *owner_id);
+
+/**
+ * \brief Check if a client has access permission
+ *
+ * \param[in] acl The subject storage_partition_acl
+ * \param[in] client_id Client ID to check
+ *
+ * \return True if access is permitted
+ */
+bool storage_partition_acl_check(
+ const struct storage_partition_acl *acl,
+ uint32_t client_id);
+
+/**
+ * \brief Authorize a requesting client
+ *
+ * \param[in] acl The subject storage_partition_acl
+ * \param[in] client_id Client ID to check
+ * \param[in] authorizer Optional authorizer
+ *
+ * \return True if access is permitted
+ */
+bool storage_partition_acl_authorize(
+ struct storage_partition_acl *acl,
+ uint32_t client_id,
+ storage_partition_authorizer authorizer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STORAGE_PARTITION_ACL_H */
diff --git a/components/service/block_storage/config/gpt/component.cmake b/components/service/block_storage/config/gpt/component.cmake
new file mode 100644
index 000000000..1e3663bf9
--- /dev/null
+++ b/components/service/block_storage/config/gpt/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/gpt_partition_configurator.c"
+ )
diff --git a/components/service/block_storage/config/gpt/gpt_partition_configurator.c b/components/service/block_storage/config/gpt/gpt_partition_configurator.c
new file mode 100644
index 000000000..cf8c6affb
--- /dev/null
+++ b/components/service/block_storage/config/gpt/gpt_partition_configurator.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <common/uuid/uuid.h>
+#include <media/disk/guid.h>
+#include <media/disk/partition_table.h>
+#include "gpt_partition_configurator.h"
+
+static bool gpt_partition_config_listener(
+ struct partitioned_block_store *subject,
+ const struct uuid_octets *partition_guid,
+ const struct storage_partition_info *back_store_info)
+{
+ /* Performs on-demand partition configuration on an attempt to
+ * open an unconfigured storage partition.
+ */
+ bool is_configured = false;
+ const partition_entry_t *partition_entry = NULL;
+
+ /* Check if matching partition entry exists in loaded GPT */
+ partition_entry = get_partition_entry_by_uuid((uuid_t *)partition_guid->octets);
+
+ if (partition_entry &&
+ back_store_info->block_size &&
+ (partition_entry->length >= back_store_info->block_size) &&
+ !(partition_entry->length % back_store_info->block_size)) {
+
+ /* Partition entry exists and values look sane */
+ uint64_t starting_lba =
+ partition_entry->start / back_store_info->block_size;
+ uint64_t ending_lba =
+ starting_lba + (partition_entry->length / back_store_info->block_size) - 1;
+
+ if (ending_lba >= starting_lba) {
+
+ is_configured = partitioned_block_store_add_partition(
+ subject, partition_guid,
+ starting_lba, ending_lba,
+ 0, NULL);
+ }
+ }
+
+ return is_configured;
+}
+
+static bool add_disk_header_partition(
+ struct partitioned_block_store *subject)
+{
+ /* Adds a partition to make the MBR/GPT readable via a separate partition. This
+ * enables clients to retrieve information from the GPT for their own configuration
+ * purposes.
+ */
+ const struct storage_partition_info *disk_info =
+ partitioned_block_store_get_back_store_info(subject);
+
+ size_t entry_table_size = PLAT_PARTITION_MAX_ENTRIES * sizeof(gpt_entry_t);
+ size_t disk_header_size = GPT_ENTRY_OFFSET + entry_table_size;
+ size_t num_header_blocks =
+ (disk_header_size + disk_info->block_size - 1) / disk_info->block_size;
+
+ if (num_header_blocks > 0 && num_header_blocks <= disk_info->num_blocks) {
+
+ struct uuid_octets partition_guid;
+
+ uuid_guid_octets_from_canonical(&partition_guid,
+ DISK_GUID_UNIQUE_PARTITION_DISK_HEADER);
+
+ uint32_t starting_lba = 0;
+ uint32_t ending_lba = starting_lba + num_header_blocks - 1;
+
+ return partitioned_block_store_add_partition(
+ subject, &partition_guid,
+ starting_lba, ending_lba,
+ 0, NULL);
+ }
+
+ return false;
+}
+
+bool gpt_partition_configure(
+ struct partitioned_block_store *subject,
+ unsigned int volume_id)
+{
+ bool success = false;
+ int result = load_partition_table(volume_id);
+
+ if ((result == 0) && add_disk_header_partition(subject)) {
+
+ partitioned_block_store_attach_config_listener(
+ subject,
+ gpt_partition_config_listener);
+
+ success = true;
+ }
+
+ return success;
+}
diff --git a/components/service/block_storage/config/gpt/gpt_partition_configurator.h b/components/service/block_storage/config/gpt/gpt_partition_configurator.h
new file mode 100644
index 000000000..2ec79e18c
--- /dev/null
+++ b/components/service/block_storage/config/gpt/gpt_partition_configurator.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef GPT_PARTITION_CONFIGURATOR_H
+#define GPT_PARTITION_CONFIGURATOR_H
+
+#include <stdbool.h>
+#include <common/uuid/uuid.h>
+#include <service/block_storage/block_store/block_store.h>
+#include <service/block_storage/block_store/partitioned/partitioned_block_store.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Configures a partitioned_block_store using a GPT
+ *
+ * Loads the GPT (if present) from the firmware volume identified by the
+ * specified volume ID and uses it to configure a set of storage partitions.
+ *
+ * \param[in] subject The subject partitioned_block_store to configure
+ * \param[in] volume_id Identifies the disk volume to read the GPT from
+ */
+bool gpt_partition_configure(
+ struct partitioned_block_store *subject,
+ unsigned int volume_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GPT_PARTITION_CONFIGURATOR_H */
diff --git a/components/service/block_storage/config/ref/component.cmake b/components/service/block_storage/config/ref/component.cmake
new file mode 100644
index 000000000..b03b1c242
--- /dev/null
+++ b/components/service/block_storage/config/ref/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ref_partition_configurator.c"
+ )
diff --git a/components/service/block_storage/config/ref/ref_partition_configurator.c b/components/service/block_storage/config/ref/ref_partition_configurator.c
new file mode 100644
index 000000000..cf6dc8668
--- /dev/null
+++ b/components/service/block_storage/config/ref/ref_partition_configurator.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include "ref_partition_configurator.h"
+
+bool ref_partition_configure(struct partitioned_block_store *subject)
+{
+ struct uuid_octets guid;
+
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_1_GUID);
+ bool is_success = partitioned_block_store_add_partition(
+ subject,
+ &guid,
+ REF_PARTITION_1_STARTING_LBA,
+ REF_PARTITION_1_ENDING_LBA,
+ 0, NULL);
+
+ if (!is_success)
+ return false;
+
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_2_GUID);
+ is_success = partitioned_block_store_add_partition(
+ subject,
+ &guid,
+ REF_PARTITION_2_STARTING_LBA,
+ REF_PARTITION_2_ENDING_LBA,
+ 0, NULL);
+
+ if (!is_success)
+ return false;
+
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_3_GUID);
+ is_success = partitioned_block_store_add_partition(
+ subject,
+ &guid,
+ REF_PARTITION_3_STARTING_LBA,
+ REF_PARTITION_3_ENDING_LBA,
+ 0, NULL);
+
+ if (!is_success)
+ return false;
+
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_4_GUID);
+ is_success = partitioned_block_store_add_partition(
+ subject,
+ &guid,
+ REF_PARTITION_4_STARTING_LBA,
+ REF_PARTITION_4_ENDING_LBA,
+ 0, NULL);
+
+ return is_success;
+}
diff --git a/components/service/block_storage/config/ref/ref_partition_configurator.h b/components/service/block_storage/config/ref/ref_partition_configurator.h
new file mode 100644
index 000000000..0ca6b7f8a
--- /dev/null
+++ b/components/service/block_storage/config/ref/ref_partition_configurator.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef REF_PARTITION_CONFIGURATOR_H
+#define REF_PARTITION_CONFIGURATOR_H
+
+#include <stdbool.h>
+#include <service/block_storage/block_store/partitioned/partitioned_block_store.h>
+#include <media/disk/guid.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * To support test, a reference storage partition configuration is used with
+ * a set of different sized partitions. The total backend block store size
+ * is kept as small as possible to allow the reference configuration to be
+ * used with a ram backed store in environments where available memory is
+ * constrained.
+ */
+
+#define REF_PARTITION_BACK_STORE_SIZE (200)
+#define REF_PARTITION_BLOCK_SIZE (256)
+
+/* About the right size for PSA storage */
+#define REF_PARTITION_1_GUID DISK_GUID_UNIQUE_PARTITION_PSA_ITS
+#define REF_PARTITION_1_STARTING_LBA (0)
+#define REF_PARTITION_1_ENDING_LBA (95)
+
+/* Also about the right size for PSA storage */
+#define REF_PARTITION_2_GUID DISK_GUID_UNIQUE_PARTITION_PSA_PS
+#define REF_PARTITION_2_STARTING_LBA (96)
+#define REF_PARTITION_2_ENDING_LBA (191)
+
+#define REF_PARTITION_3_GUID DISK_GUID_UNIQUE_PARTITION_PRIMARY_FWU_METADATA
+#define REF_PARTITION_3_STARTING_LBA (192)
+#define REF_PARTITION_3_ENDING_LBA (195)
+
+#define REF_PARTITION_4_GUID DISK_GUID_UNIQUE_PARTITION_BACKUP_FWU_METADATA
+#define REF_PARTITION_4_STARTING_LBA (196)
+#define REF_PARTITION_4_ENDING_LBA (199)
+
+/**
+ * \brief Configures a partitioned_block_store with the reference configuration
+ *
+ * \param[in] subject The subject partitioned_block_store
+ */
+bool ref_partition_configure(struct partitioned_block_store *subject);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* REF_PARTITION_CONFIGURATOR_H */
diff --git a/components/service/block_storage/factory/block_store_factory.h b/components/service/block_storage/factory/block_store_factory.h
new file mode 100644
index 000000000..a45f51765
--- /dev/null
+++ b/components/service/block_storage/factory/block_store_factory.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BLOCK_STORE_FACTORY_H
+#define BLOCK_STORE_FACTORY_H
+
+#include <util.h>
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Defines a common interface for constructing the block_store
+ * stack needed for a deployment. The concrete factory will depend
+ * on which factory component has been deployed. This interface
+ * is only intended to be used where only one type block store
+ * factory is needed in a deployment. This ifdef allows multiple
+ * block_store factory methods to be combined within a single build,
+ * each with a distinct function name. This is needed for some test
+ * deployments where different block_store stacks are constructed
+ * for different test cases.
+ */
+#ifdef CONCRETE_BLOCK_STORE_FACTORY
+
+#define BLOCK_STORE_FACTORY_FUNC_CREATE CONCAT(CONCRETE_BLOCK_STORE_FACTORY, _create)
+#define BLOCK_STORE_FACTORY_FUNC_DESTROY CONCAT(CONCRETE_BLOCK_STORE_FACTORY, _destroy)
+
+struct block_store *BLOCK_STORE_FACTORY_FUNC_CREATE(void);
+void BLOCK_STORE_FACTORY_FUNC_DESTROY(struct block_store *block_store);
+
+#endif
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+static inline struct block_store *block_store_factory_create(void)
+{
+#ifdef CONCRETE_BLOCK_STORE_FACTORY
+ return BLOCK_STORE_FACTORY_FUNC_CREATE();
+#else
+ #error No concrete block store factory
+#endif
+}
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store The block store to destroy
+ */
+static inline void block_store_factory_destroy(struct block_store *block_store)
+{
+#ifdef CONCRETE_BLOCK_STORE_FACTORY
+ return BLOCK_STORE_FACTORY_FUNC_DESTROY(block_store);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/client/block_store_factory.c b/components/service/block_storage/factory/client/block_store_factory.c
new file mode 100644
index 000000000..842ca4d15
--- /dev/null
+++ b/components/service/block_storage/factory/client/block_store_factory.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include "service/block_storage/block_store/client/block_storage_client.h"
+#include "protocols/rpc/common/packed-c/encoding.h"
+#include "service_locator.h"
+
+struct block_store_assembly {
+ struct block_storage_client client;
+ struct rpc_caller_session *rpc_session;
+ struct service_context *service_context;
+};
+
+struct block_store *client_block_store_factory_create(const char *sn)
+{
+ struct block_store *product = NULL;
+ struct block_store_assembly *assembly =
+ (struct block_store_assembly *)calloc(1, sizeof(struct block_store_assembly));
+
+ if (assembly) {
+
+ assembly->rpc_session = NULL;
+ assembly->service_context = NULL;
+
+ service_locator_init();
+
+ assembly->service_context = service_locator_query(sn);
+
+ if (assembly->service_context) {
+
+ assembly->rpc_session = service_context_open(assembly->service_context);
+
+ if (assembly->rpc_session)
+ product = block_storage_client_init(&assembly->client, assembly->rpc_session);
+ }
+
+ if (!product) {
+
+ /* Something went wrong! */
+ free(assembly);
+ }
+ }
+
+ return product;
+}
+
+void client_block_store_factory_destroy(struct block_store *block_store)
+{
+ if (block_store) {
+
+ size_t offset_into_assembly =
+ offsetof(struct block_store_assembly, client) +
+ offsetof(struct block_storage_client, base_block_store);
+
+ struct block_store_assembly *assembly = (struct block_store_assembly *)
+ ((uint8_t *)block_store - offset_into_assembly);
+
+ block_storage_client_deinit(&assembly->client);
+
+ if (assembly->service_context) {
+
+ if (assembly->rpc_session) {
+ service_context_close(
+ assembly->service_context, assembly->rpc_session);
+ assembly->rpc_session = NULL;
+ }
+
+ service_context_relinquish(assembly->service_context);
+ assembly->service_context = NULL;
+ }
+
+ free(assembly);
+ }
+}
diff --git a/components/service/block_storage/factory/client/block_store_factory.h b/components/service/block_storage/factory/client/block_store_factory.h
new file mode 100644
index 000000000..6feebf496
--- /dev/null
+++ b/components/service/block_storage/factory/client/block_store_factory.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CLIENT_BLOCK_STORE_FACTORY_H
+#define CLIENT_BLOCK_STORE_FACTORY_H
+
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A block store factory that constructs a block_storage_client
+ * (which is a block_store specialization). The constructed client
+ * establishes a session with the discovered block storage service
+ * provider.
+ */
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \param[in] sn Service name identifying block storage provider
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+struct block_store *client_block_store_factory_create(const char *sn);
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store The block store to destroy
+ */
+void client_block_store_factory_destroy(struct block_store *block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CLIENT_BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/client/component.cmake b/components/service/block_storage/factory/client/component.cmake
new file mode 100644
index 000000000..759da54e5
--- /dev/null
+++ b/components/service/block_storage/factory/client/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_store_factory.c"
+ )
diff --git a/components/service/block_storage/factory/file/block_store_factory.c b/components/service/block_storage/factory/file/block_store_factory.c
new file mode 100644
index 000000000..c6915107b
--- /dev/null
+++ b/components/service/block_storage/factory/file/block_store_factory.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "block_store_factory.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "media/volume/block_volume/block_volume.h"
+#include "media/volume/index/volume_index.h"
+#include "service/block_storage/block_store/device/file/file_block_store.h"
+#include "service/block_storage/block_store/partitioned/partitioned_block_store.h"
+#include "service/block_storage/config/gpt/gpt_partition_configurator.h"
+#include "trace.h"
+
+#ifndef FILE_BLOCK_SIZE
+/* Default to most common block size for UEFI volumes */
+#define FILE_BLOCK_SIZE (512)
+#endif
+
+static char disk_img_filename[256];
+
+struct block_store_assembly {
+ struct file_block_store file_block_store;
+ struct partitioned_block_store partitioned_block_store;
+ struct block_volume volume;
+};
+
+static void tear_down_assembly(struct block_store_assembly *assembly)
+{
+ volume_index_clear();
+
+ if (assembly) {
+ partitioned_block_store_deinit(&assembly->partitioned_block_store);
+ file_block_store_deinit(&assembly->file_block_store);
+ block_volume_deinit(&assembly->volume);
+
+ free(assembly);
+ }
+}
+
+struct block_store *file_block_store_factory_create(void)
+{
+ struct block_store *product = NULL;
+ struct block_store_assembly *assembly =
+ (struct block_store_assembly *)malloc(sizeof(struct block_store_assembly));
+
+ if (assembly) {
+ struct uuid_octets disk_guid;
+ memset(&disk_guid, 0, sizeof(disk_guid));
+
+ volume_index_init();
+
+ /* Ensure disk image filename is set */
+ if (disk_img_filename[0] == '\0')
+ file_block_store_factory_set_filename("secure-flash.img");
+
+ /* Initialise a file_block_store to provide underlying storage */
+ struct block_store *secure_flash = file_block_store_init(
+ &assembly->file_block_store, disk_img_filename, FILE_BLOCK_SIZE);
+
+ if (secure_flash) {
+ /* Secure flash successfully initialized so create a block_volume
+ * associated with secure flash block store to enable it to be
+ * accessed as a storage volume.
+ */
+ struct volume *volume = NULL;
+
+ int result = block_volume_init(&assembly->volume, secure_flash, &disk_guid,
+ &volume);
+
+ if (result == 0) {
+ volume_index_add(VOLUME_ID_SECURE_FLASH, volume);
+
+ /* Stack a partitioned_block_store over the back store */
+ product = partitioned_block_store_init(
+ &assembly->partitioned_block_store, 0, &disk_guid,
+ secure_flash, NULL);
+
+ if (product) {
+ /* Successfully created the block store stack so configure the
+ * partitions if there are any described in the GPT. No GPT
+ * is a valid configuration option so it's deliberately not
+ * treated as an error. To help a platform integrator who
+ * intended to use a GPT, a message is output if partitions
+ * weren't configured.
+ * */
+ bool is_configured = gpt_partition_configure(
+ &assembly->partitioned_block_store,
+ VOLUME_ID_SECURE_FLASH);
+
+ if (!is_configured)
+ IMSG("No GPT detected in %s", disk_img_filename);
+
+ } else
+ EMSG("Failed to init partitioned_block_store");
+ }
+ } else
+ EMSG("Failed to init file_block_store: %s", disk_img_filename);
+
+ if (!product) {
+ /* Something went wrong! */
+ tear_down_assembly(assembly);
+ }
+ } else
+ EMSG("Failed to alloc file_block_store assembly");
+
+ return product;
+}
+
+void file_block_store_factory_destroy(struct block_store *block_store)
+{
+ if (block_store) {
+ size_t offset_into_assembly =
+ offsetof(struct block_store_assembly, partitioned_block_store) +
+ offsetof(struct partitioned_block_store, base_block_store);
+
+ struct block_store_assembly *assembly =
+ (struct block_store_assembly *)((uint8_t *)block_store -
+ offset_into_assembly);
+
+ tear_down_assembly(assembly);
+ }
+}
+
+void file_block_store_factory_set_filename(const char *filename)
+{
+ strncpy(disk_img_filename, filename, sizeof(disk_img_filename));
+
+ /* Ensure that filename is null terminated */
+ disk_img_filename[sizeof(disk_img_filename) - 1] = '\0';
+} \ No newline at end of file
diff --git a/components/service/block_storage/factory/file/block_store_factory.h b/components/service/block_storage/factory/file/block_store_factory.h
new file mode 100644
index 000000000..c37513f15
--- /dev/null
+++ b/components/service/block_storage/factory/file/block_store_factory.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FILE_BLOCK_STORE_FACTORY_H
+#define FILE_BLOCK_STORE_FACTORY_H
+
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A block store factory that constructs a partitioned block store backed
+ * by a file block device that provides access to a disk image file.
+ * If the disk image contains a GPT, it will be used to configure a set
+ * of storage partitions.
+ *
+ * This factory is intended for deployments where Posix filesystem
+ * access is possible with access to a a disk image file.
+ */
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+struct block_store *file_block_store_factory_create(void);
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store The block store to destroy
+ */
+void file_block_store_factory_destroy(struct block_store *block_store);
+
+/**
+ * \brief Set the filename for the disk image file
+ *
+ * \param[in] filename Disk image filename
+ */
+void file_block_store_factory_set_filename(const char *filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FILE_BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/file/component.cmake b/components/service/block_storage/factory/file/component.cmake
new file mode 100644
index 000000000..644f03972
--- /dev/null
+++ b/components/service/block_storage/factory/file/component.cmake
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_store_factory.c"
+ )
+
+# If none already defined, make this the default factory for the deployment
+if (NOT DEFINED TS_BLOCK_STORE_FACTORY)
+ set(TS_BLOCK_STORE_FACTORY "file_block_store_factory")
+ target_compile_definitions(${TGT} PRIVATE
+ CONCRETE_BLOCK_STORE_FACTORY=${TS_BLOCK_STORE_FACTORY})
+endif() \ No newline at end of file
diff --git a/components/service/block_storage/factory/ref_ram/block_store_factory.c b/components/service/block_storage/factory/ref_ram/block_store_factory.c
new file mode 100644
index 000000000..631a933d8
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram/block_store_factory.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "block_store_factory.h"
+#include "service/block_storage/block_store/device/ram/ram_block_store.h"
+#include "service/block_storage/block_store/partitioned/partitioned_block_store.h"
+#include "service/block_storage/config/ref/ref_partition_configurator.h"
+
+struct block_store_assembly {
+ struct ram_block_store ram_block_store;
+ struct partitioned_block_store partitioned_block_store;
+};
+
+struct block_store *ref_ram_block_store_factory_create(void)
+{
+ struct block_store *product = NULL;
+ struct block_store_assembly *assembly =
+ (struct block_store_assembly *)calloc(1, sizeof(struct block_store_assembly));
+
+ if (assembly) {
+
+ struct uuid_octets back_store_guid;
+
+ memset(&back_store_guid, 0, sizeof(back_store_guid));
+
+ /* Initialise a ram_block_store to provide underlying storage */
+ struct block_store *back_store = ram_block_store_init(
+ &assembly->ram_block_store,
+ &back_store_guid,
+ REF_PARTITION_BACK_STORE_SIZE,
+ REF_PARTITION_BLOCK_SIZE);
+
+ /* Stack a partitioned_block_store over the back store */
+ product = partitioned_block_store_init(
+ &assembly->partitioned_block_store,
+ 0,
+ &back_store_guid,
+ back_store,
+ NULL);
+
+ /* Use the reference partition configuration */
+ ref_partition_configure(&assembly->partitioned_block_store);
+
+ if (!product) {
+
+ /* Something went wrong! */
+ free(assembly);
+ }
+ }
+
+ return product;
+}
+
+void ref_ram_block_store_factory_destroy(struct block_store *block_store)
+{
+ if (block_store) {
+
+ size_t offset_into_assembly =
+ offsetof(struct block_store_assembly, partitioned_block_store) +
+ offsetof(struct partitioned_block_store, base_block_store);
+
+ struct block_store_assembly *assembly = (struct block_store_assembly *)
+ ((uint8_t *)block_store - offset_into_assembly);
+
+ partitioned_block_store_deinit(&assembly->partitioned_block_store);
+ ram_block_store_deinit(&assembly->ram_block_store);
+
+ free(assembly);
+ }
+}
diff --git a/components/service/block_storage/factory/ref_ram/block_store_factory.h b/components/service/block_storage/factory/ref_ram/block_store_factory.h
new file mode 100644
index 000000000..189d208ec
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram/block_store_factory.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef REF_RAM_BLOCK_STORE_FACTORY_H
+#define REF_RAM_BLOCK_STORE_FACTORY_H
+
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A block store factory that constructs a partitioned block store with
+ * a ram back store. The reference partition configuration is used to
+ * provide a set of storage partitions that match the expectations of
+ * test cases. This factory should only really be used for test deployments.
+ */
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+struct block_store *ref_ram_block_store_factory_create(void);
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store The block store to destroy
+ */
+void ref_ram_block_store_factory_destroy(struct block_store *block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* REF_RAM_BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/ref_ram/component.cmake b/components/service/block_storage/factory/ref_ram/component.cmake
new file mode 100644
index 000000000..7277cb396
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram/component.cmake
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_store_factory.c"
+ )
+
+# If none already defined, make this the default factory for the deployment
+if (NOT DEFINED TS_BLOCK_STORE_FACTORY)
+ set(TS_BLOCK_STORE_FACTORY "ref_ram_block_store_factory")
+ target_compile_definitions(${TGT} PRIVATE
+ CONCRETE_BLOCK_STORE_FACTORY=${TS_BLOCK_STORE_FACTORY})
+endif() \ No newline at end of file
diff --git a/components/service/block_storage/factory/ref_ram_gpt/block_store_factory.c b/components/service/block_storage/factory/ref_ram_gpt/block_store_factory.c
new file mode 100644
index 000000000..d72e6aa77
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram_gpt/block_store_factory.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <service/block_storage/block_store/device/ram/ram_block_store.h>
+#include <service/block_storage/block_store/partitioned/partitioned_block_store.h>
+#include <service/block_storage/config/ref/ref_partition_configurator.h>
+#include <service/block_storage/config/gpt/gpt_partition_configurator.h>
+#include <media/volume/index/volume_index.h>
+#include <media/volume/block_volume/block_volume.h>
+#include <media/disk/disk_images/ref_partition.h>
+#include <media/disk/formatter/disk_formatter.h>
+#include "block_store_factory.h"
+
+struct block_store_assembly
+{
+ struct ram_block_store ram_block_store;
+ struct partitioned_block_store partitioned_block_store;
+ struct block_volume volume;
+};
+
+static void tear_down_assembly(struct block_store_assembly *assembly)
+{
+ volume_index_clear();
+
+ partitioned_block_store_deinit(&assembly->partitioned_block_store);
+ ram_block_store_deinit(&assembly->ram_block_store);
+ block_volume_deinit(&assembly->volume);
+
+ free(assembly);
+}
+
+struct block_store *ref_ram_gpt_block_store_factory_create(void)
+{
+ struct block_store *product = NULL;
+ struct block_store_assembly *assembly =
+ (struct block_store_assembly*)malloc(sizeof(struct block_store_assembly));
+
+ if (assembly) {
+
+ struct uuid_octets disk_guid;
+ memset(&disk_guid, 0, sizeof(disk_guid));
+
+ volume_index_init();
+
+ /* Check assumptions about generated ref_partition data */
+ assert(!(ref_partition_data_length % REF_PARTITION_BLOCK_SIZE));
+
+ /* Initialise a ram_block_store to mimic the secure flash used
+ * to provide underlying storage.
+ */
+ struct block_store *secure_flash = ram_block_store_init(
+ &assembly->ram_block_store,
+ &disk_guid,
+ ref_partition_data_length / REF_PARTITION_BLOCK_SIZE,
+ REF_PARTITION_BLOCK_SIZE);
+
+ if (secure_flash) {
+
+ /* Secure flash successfully initialized so create a block_volume to
+ * enable it to be accessed as a storage volume. The created io_dev is
+ * used to initialize the flash with the reference disk image.
+ */
+ struct volume *volume = NULL;
+
+ if (!block_volume_init(&assembly->volume,
+ secure_flash, &disk_guid, &volume) &&
+ !disk_formatter_clone(
+ volume->dev_handle, volume->io_spec,
+ ref_partition_data, ref_partition_data_length)) {
+
+ volume_index_add(VOLUME_ID_SECURE_FLASH, volume);
+
+ /* Stack a partitioned_block_store over the back store */
+ product = partitioned_block_store_init(
+ &assembly->partitioned_block_store, 0,
+ &disk_guid,
+ secure_flash,
+ NULL);
+
+ if (product) {
+
+ /* Successfully created the block store stack so configure the
+ * partitions if there are any described in the GPT.
+ */
+ gpt_partition_configure(
+ &assembly->partitioned_block_store,
+ VOLUME_ID_SECURE_FLASH);
+ }
+ }
+ }
+
+ if (!product) {
+
+ /* Something went wrong! */
+ tear_down_assembly(assembly);
+ }
+ }
+
+ return product;
+}
+
+void ref_ram_gpt_block_store_factory_destroy(struct block_store *block_store)
+{
+ if (block_store) {
+
+ size_t offset_into_assembly =
+ offsetof(struct block_store_assembly, partitioned_block_store) +
+ offsetof(struct partitioned_block_store, base_block_store);
+
+ struct block_store_assembly *assembly = (struct block_store_assembly*)
+ ((uint8_t*)block_store - offset_into_assembly);
+
+ tear_down_assembly(assembly);
+ }
+}
diff --git a/components/service/block_storage/factory/ref_ram_gpt/block_store_factory.h b/components/service/block_storage/factory/ref_ram_gpt/block_store_factory.h
new file mode 100644
index 000000000..4c706fa1c
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram_gpt/block_store_factory.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef REF_RAM_GPT_BLOCK_STORE_FACTORY_H
+#define REF_RAM_GPT_BLOCK_STORE_FACTORY_H
+
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A block store factory that constructs a partitioned block store with
+ * a ram back store. The ram back store is is formatted during construction
+ * to contain a GPT that describes the reference set of partitions that
+ * many test cases depend on.
+ */
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+struct block_store *ref_ram_gpt_block_store_factory_create(void);
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store The block store to destroy
+ */
+void ref_ram_gpt_block_store_factory_destroy(struct block_store *block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* REF_RAM_GPT_BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/ref_ram_gpt/component.cmake b/components/service/block_storage/factory/ref_ram_gpt/component.cmake
new file mode 100644
index 000000000..166c55a34
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram_gpt/component.cmake
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_store_factory.c"
+ )
+
+# If none already defined, make this the default factory for the deployment
+if (NOT DEFINED TS_BLOCK_STORE_FACTORY)
+ set(TS_BLOCK_STORE_FACTORY "ref_ram_gpt_block_store_factory")
+ target_compile_definitions(${TGT} PRIVATE
+ CONCRETE_BLOCK_STORE_FACTORY=${TS_BLOCK_STORE_FACTORY})
+endif() \ No newline at end of file
diff --git a/components/service/block_storage/factory/rpmb/block_store_factory.c b/components/service/block_storage/factory/rpmb/block_store_factory.c
new file mode 100644
index 000000000..22acd4b03
--- /dev/null
+++ b/components/service/block_storage/factory/rpmb/block_store_factory.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "block_store_factory.h"
+#include "service/block_storage/block_store/device/rpmb/rpmb_block_store.h"
+#include "service/block_storage/block_store/partitioned/partitioned_block_store.h"
+#include "service/block_storage/config/gpt/gpt_partition_configurator.h"
+#include "service/rpmb/frontend/platform/default/rpmb_platform_default.h"
+#include "service/rpmb/client/rpmb_client.h"
+#include "service/locator/interface/service_locator.h"
+#include <media/volume/index/volume_index.h>
+#include <media/volume/block_volume/block_volume.h>
+#include <media/disk/disk_images/ref_partition.h>
+#include <media/disk/formatter/disk_formatter.h>
+
+struct block_store_assembly {
+ struct rpmb_block_store rpmb_block_store;
+ struct service_context *service_context;
+ struct rpc_caller_session *rpc_session;
+ struct rpmb_client rpmb_client;
+
+ struct rpmb_frontend rpmb_frontend;
+ struct rpmb_platform_default rpmb_platform;
+ struct rpmb_backend rpmb_backend;
+
+ struct partitioned_block_store partitioned_block_store;
+ struct block_volume volume;
+};
+
+struct block_store *rpmb_block_store_factory_create(void)
+{
+ struct block_store *product = NULL;
+ struct block_store *rpmb_store = NULL;
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_platform *platform = NULL;
+ struct rpmb_backend *backend = NULL;
+ struct block_store_assembly *assembly = NULL;
+ struct uuid_octets back_store_guid = { 0 };
+ struct volume *volume = NULL;
+ struct uuid_octets disk_guid = { 0 };
+
+ assembly = (struct block_store_assembly *)calloc(1, sizeof(struct block_store_assembly));
+ if (!assembly)
+ return NULL;
+
+ service_locator_init();
+
+ assembly->service_context = service_locator_query("sn:trustedfirmware.org:rpmb:0");
+ if (!assembly->service_context)
+ goto error5;
+
+ assembly->rpc_session = service_context_open(assembly->service_context);
+ if (!assembly->rpc_session)
+ goto error5;
+
+ backend = rpmb_client_init(&assembly->rpmb_client, assembly->rpc_session);
+ if (!backend)
+ goto error4;
+
+ platform = rpmb_platform_default_init(&assembly->rpmb_platform);
+ if (!platform)
+ goto error3;
+
+ status = rpmb_frontend_create(&assembly->rpmb_frontend, platform, backend, 0);
+ if (status != PSA_SUCCESS)
+ goto error3;
+
+ status = rpmb_frontend_init(&assembly->rpmb_frontend);
+ if (status != PSA_SUCCESS)
+ goto error3;
+
+ rpmb_store = rpmb_block_store_init(&assembly->rpmb_block_store, &back_store_guid,
+ &assembly->rpmb_frontend);
+ if (!rpmb_store)
+ goto error2;
+
+ volume_index_init();
+
+ if (block_volume_init(&assembly->volume, rpmb_store, &disk_guid, &volume) ||
+ disk_formatter_clone(volume->dev_handle, volume->io_spec, ref_partition_data,
+ ref_partition_data_length))
+ goto error1;
+
+ if (volume_index_add(VOLUME_ID_SECURE_FLASH, volume))
+ goto error1;
+
+ product = partitioned_block_store_init(&assembly->partitioned_block_store, 0,
+ &disk_guid, rpmb_store, NULL);
+ if (!product)
+ goto error1;
+
+ if (!gpt_partition_configure(&assembly->partitioned_block_store, VOLUME_ID_SECURE_FLASH))
+ goto error1;
+
+ return product;
+
+error1:
+ rpmb_block_store_deinit(&assembly->rpmb_block_store);
+
+error2:
+ rpmb_frontend_destroy(&assembly->rpmb_frontend);
+
+error3:
+ rpmb_client_deinit(&assembly->rpmb_client);
+
+error4:
+ service_context_close(assembly->service_context, assembly->rpc_session);
+
+error5:
+ free(assembly);
+
+ return NULL;
+}
+
+void rpmb_block_store_factory_destroy(struct block_store *block_store)
+{
+ if (!block_store)
+ return;
+
+ size_t offset_into_assembly =
+ offsetof(struct block_store_assembly, partitioned_block_store) +
+ offsetof(struct partitioned_block_store, base_block_store);
+
+ struct block_store_assembly *assembly = (struct block_store_assembly *)
+ ((uint8_t *)block_store - offset_into_assembly);
+
+ partitioned_block_store_deinit(&assembly->partitioned_block_store);
+
+ rpmb_block_store_deinit(&assembly->rpmb_block_store);
+ rpmb_frontend_destroy(&assembly->rpmb_frontend);
+ rpmb_client_deinit(&assembly->rpmb_client);
+ service_context_close(assembly->service_context, assembly->rpc_session);
+
+ free(assembly);
+}
diff --git a/components/service/block_storage/factory/rpmb/block_store_factory.h b/components/service/block_storage/factory/rpmb/block_store_factory.h
new file mode 100644
index 000000000..3f5e8e8ba
--- /dev/null
+++ b/components/service/block_storage/factory/rpmb/block_store_factory.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef RPMB_BLOCK_STORE_FACTORY_H
+#define RPMB_BLOCK_STORE_FACTORY_H
+
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A block store factory that constructs a partitioned block store with
+ * an RPMB back store. The reference partition configuration is used to
+ * provide a set of storage partitions that match the expectations of
+ * test cases. This factory should only really be used for test deployments.
+ */
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+struct block_store *rpmb_block_store_factory_create(void);
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store The block store to destroy
+ */
+void rpmb_block_store_factory_destroy(struct block_store *block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/rpmb/component.cmake b/components/service/block_storage/factory/rpmb/component.cmake
new file mode 100644
index 000000000..633f40205
--- /dev/null
+++ b/components/service/block_storage/factory/rpmb/component.cmake
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_store_factory.c"
+ )
+
+# If none already defined, make this the default factory for the deployment
+if (NOT DEFINED TS_BLOCK_STORE_FACTORY)
+ set(TS_BLOCK_STORE_FACTORY "rpmb_block_store_factory")
+ target_compile_definitions(${TGT} PRIVATE
+ CONCRETE_BLOCK_STORE_FACTORY=${TS_BLOCK_STORE_FACTORY})
+endif() \ No newline at end of file
diff --git a/components/service/block_storage/factory/semihosting/block_store_factory.c b/components/service/block_storage/factory/semihosting/block_store_factory.c
new file mode 100644
index 000000000..8e58e3638
--- /dev/null
+++ b/components/service/block_storage/factory/semihosting/block_store_factory.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+#include "block_store_factory.h"
+#include "service/block_storage/block_store/device/semihosting/semihosting_block_store.h"
+#include "service/block_storage/block_store/partitioned/partitioned_block_store.h"
+#include "service/block_storage/config/gpt/gpt_partition_configurator.h"
+#include "media/volume/index/volume_index.h"
+#include "media/volume/block_volume/block_volume.h"
+
+/* Most common block size for UEFI volumes */
+#define SEMIHOSTING_BLOCK_SIZE (512)
+
+struct block_store_assembly
+{
+ struct semihosting_block_store semihosting_block_store;
+ struct partitioned_block_store partitioned_block_store;
+ struct block_volume volume;
+};
+
+static void tear_down_assembly(struct block_store_assembly *assembly)
+{
+ volume_index_clear();
+
+ partitioned_block_store_deinit(&assembly->partitioned_block_store);
+ semihosting_block_store_deinit(&assembly->semihosting_block_store);
+ block_volume_deinit(&assembly->volume);
+
+ free(assembly);
+}
+
+struct block_store *semihosting_block_store_factory_create(void)
+{
+ struct block_store *product = NULL;
+ struct block_store_assembly *assembly =
+ (struct block_store_assembly*)malloc(sizeof(struct block_store_assembly));
+
+ if (assembly) {
+
+ struct uuid_octets disk_guid;
+ memset(&disk_guid, 0, sizeof(disk_guid));
+
+ volume_index_init();
+
+ /* Initialise a semihosting_block_store to provide underlying storage */
+ struct block_store *secure_flash = semihosting_block_store_init(
+ &assembly->semihosting_block_store,
+ "secure-flash.img",
+ SEMIHOSTING_BLOCK_SIZE);
+
+ if (secure_flash) {
+
+ /* Secure flash successfully initialized so create a block_volume
+ * associated with secure flash block store to enable it to be
+ * accessed as a storage volume.
+ */
+ struct volume *volume = NULL;
+
+ int result = block_volume_init(&assembly->volume,
+ secure_flash, &disk_guid,
+ &volume);
+
+ if (result == 0) {
+
+ volume_index_add(VOLUME_ID_SECURE_FLASH, volume);
+
+ /* Stack a partitioned_block_store over the back store */
+ product = partitioned_block_store_init(
+ &assembly->partitioned_block_store,
+ 0,
+ &disk_guid,
+ secure_flash,
+ NULL);
+
+ if (product) {
+
+ /* Successfully created the block store stack so configure the
+ * partitions if there are any described in the GPT. No GPT
+ * is a valid configuration option so it's deliberately not
+ * treated as an error. To help a platform integrator who
+ * intended to use a GPT, a message is output if partitions
+ * weren't configured.
+ * */
+ bool is_configured = gpt_partition_configure(
+ &assembly->partitioned_block_store,
+ VOLUME_ID_SECURE_FLASH);
+
+ if (!is_configured)
+ IMSG("No GPT detected\n");
+ }
+ }
+ }
+
+ if (!product) {
+
+ /* Something went wrong! */
+ tear_down_assembly(assembly);
+ }
+ }
+
+ return product;
+}
+
+void semihosting_block_store_factory_destroy(struct block_store *block_store)
+{
+ if (block_store) {
+
+ size_t offset_into_assembly =
+ offsetof(struct block_store_assembly, partitioned_block_store) +
+ offsetof(struct partitioned_block_store, base_block_store);
+
+ struct block_store_assembly *assembly = (struct block_store_assembly*)
+ ((uint8_t*)block_store - offset_into_assembly);
+
+ tear_down_assembly(assembly);
+ }
+}
diff --git a/components/service/block_storage/factory/semihosting/block_store_factory.h b/components/service/block_storage/factory/semihosting/block_store_factory.h
new file mode 100644
index 000000000..c1c2f0399
--- /dev/null
+++ b/components/service/block_storage/factory/semihosting/block_store_factory.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SEMIHOSTING_BLOCK_STORE_FACTORY_H
+#define SEMIHOSTING_BLOCK_STORE_FACTORY_H
+
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A block store factory that constructs a partitioned block store backed
+ * by a semihosting block device that provides access to a disk image file
+ * residing in the host's filesystem. If the disk image contains a GPT, it
+ * will be used to configure a set of storage partitions.
+ *
+ * Semihosting is an Arm debug facility that enables device software to
+ * communicate with the host. Can be used in emulated environments (FVP &
+ * QEMU) and with real hardware with a suitable debugger.
+ */
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+struct block_store *semihosting_block_store_factory_create(void);
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store The block store to destroy
+ */
+void semihosting_block_store_factory_destroy(struct block_store *block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SEMIHOSTING_BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/semihosting/component.cmake b/components/service/block_storage/factory/semihosting/component.cmake
new file mode 100644
index 000000000..97affaf49
--- /dev/null
+++ b/components/service/block_storage/factory/semihosting/component.cmake
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_store_factory.c"
+ )
+
+# If none already defined, make this the default factory for the deployment
+if (NOT DEFINED TS_BLOCK_STORE_FACTORY)
+ set(TS_BLOCK_STORE_FACTORY "semihosting_block_store_factory")
+ target_compile_definitions(${TGT} PRIVATE
+ CONCRETE_BLOCK_STORE_FACTORY=${TS_BLOCK_STORE_FACTORY})
+endif() \ No newline at end of file
diff --git a/components/service/block_storage/provider/block_storage_provider.c b/components/service/block_storage/provider/block_storage_provider.c
new file mode 100644
index 000000000..e3b4f2858
--- /dev/null
+++ b/components/service/block_storage/provider/block_storage_provider.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "protocols/service/block_storage/packed-c/opcodes.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "block_storage_provider.h"
+#include "block_storage_uuid.h"
+
+/* Service request handlers */
+static rpc_status_t get_partition_info_handler(void *context, struct rpc_request *req);
+static rpc_status_t open_handler(void *context, struct rpc_request *req);
+static rpc_status_t close_handler(void *context, struct rpc_request *req);
+static rpc_status_t read_handler(void *context, struct rpc_request *req);
+static rpc_status_t write_handler(void *context, struct rpc_request *req);
+static rpc_status_t erase_handler(void *context, struct rpc_request *req);
+
+/* Handler mapping table for service */
+static const struct service_handler handler_table[] = {
+ {TS_BLOCK_STORAGE_OPCODE_GET_PARTITION_INFO, get_partition_info_handler},
+ {TS_BLOCK_STORAGE_OPCODE_OPEN, open_handler},
+ {TS_BLOCK_STORAGE_OPCODE_CLOSE, close_handler},
+ {TS_BLOCK_STORAGE_OPCODE_READ, read_handler},
+ {TS_BLOCK_STORAGE_OPCODE_WRITE, write_handler},
+ {TS_BLOCK_STORAGE_OPCODE_ERASE, erase_handler}
+};
+
+struct rpc_service_interface *block_storage_provider_init(
+ struct block_storage_provider *context,
+ struct block_store *block_store)
+{
+ struct rpc_service_interface *rpc_interface = NULL;
+ const struct rpc_uuid block_storage_service_uuid = {
+ .uuid = TS_BLOCK_STORAGE_SERVICE_UUID
+ };
+
+ if (context) {
+ context->serializer = NULL;
+
+ context->block_store = block_store;
+
+ service_provider_init(&context->base_provider, context, &block_storage_service_uuid,
+ handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+
+ rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+ }
+
+ return rpc_interface;
+}
+
+void block_storage_provider_deinit(
+ struct block_storage_provider *context)
+{
+ (void)context;
+}
+
+void block_storage_provider_register_serializer(
+ struct block_storage_provider *context,
+ const struct block_storage_serializer *serializer)
+{
+ context->serializer = serializer;
+}
+
+static const struct block_storage_serializer* get_block_storage_serializer(
+ struct block_storage_provider *context,
+ const struct rpc_request *req)
+{
+
+ return context->serializer;
+}
+
+static rpc_status_t get_partition_info_handler(void *context, struct rpc_request *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ struct uuid_octets partition_guid = {0};
+
+ if (serializer)
+ rpc_status = serializer->deserialize_get_partition_info_req(&req->request,
+ &partition_guid);
+
+ if (rpc_status == RPC_SUCCESS) {
+
+ struct storage_partition_info partition_info;
+
+ psa_status_t op_status = block_store_get_partition_info(
+ this_instance->block_store,
+ &partition_guid,
+ &partition_info);
+
+ req->service_status = op_status;
+
+ if (op_status == PSA_SUCCESS)
+ rpc_status = serializer->serialize_get_partition_info_resp(
+ &req->response, &partition_info);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t open_handler(void *context, struct rpc_request *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ struct uuid_octets partition_guid = {0};
+
+ if (serializer)
+ rpc_status = serializer->deserialize_open_req(&req->request, &partition_guid);
+
+ if (rpc_status == RPC_SUCCESS) {
+
+ storage_partition_handle_t handle = 0;
+
+ psa_status_t op_status = block_store_open(
+ this_instance->block_store,
+ req->source_id,
+ &partition_guid,
+ &handle);
+
+ req->service_status = op_status;
+
+ if (op_status == PSA_SUCCESS) {
+ rpc_status = serializer->serialize_open_resp(&req->response, handle);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t close_handler(void *context, struct rpc_request *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ struct rpc_buffer *req_buf = &req->request;
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ storage_partition_handle_t handle = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_close_req(req_buf, &handle);
+
+ if (rpc_status == RPC_SUCCESS) {
+
+ psa_status_t op_status = block_store_close(
+ this_instance->block_store,
+ req->source_id,
+ handle);
+
+ req->service_status = op_status;
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t read_handler(void *context, struct rpc_request *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ struct rpc_buffer *req_buf = &req->request;
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ storage_partition_handle_t handle = 0;
+ uint64_t lba = 0;
+ size_t offset = 0;
+ size_t len = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_read_req(req_buf, &handle, &lba, &offset, &len);
+
+ if (rpc_status == RPC_SUCCESS) {
+ /* Defend against oversize read length */
+ if (len > req->response.size)
+ len = req->response.size;
+
+ psa_status_t op_status = block_store_read(
+ this_instance->block_store,
+ req->source_id,
+ handle,
+ lba,
+ offset,
+ len,
+ (uint8_t *)req->response.data,
+ &req->response.data_length);
+
+ req->service_status = op_status;
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t write_handler(void *context, struct rpc_request *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ struct rpc_buffer *req_buf = &req->request;
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ storage_partition_handle_t handle = 0;
+ uint64_t lba = 0;
+ size_t offset = 0;
+ const uint8_t *data = NULL;
+ size_t data_len = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_write_req(req_buf, &handle, &lba,
+ &offset, &data, &data_len);
+
+ if (rpc_status == RPC_SUCCESS) {
+
+ size_t num_written = 0;
+
+ psa_status_t op_status = block_store_write(
+ this_instance->block_store,
+ req->source_id,
+ handle,
+ lba,
+ offset,
+ data,
+ data_len,
+ &num_written);
+
+ req->service_status = op_status;
+
+ if (op_status == PSA_SUCCESS) {
+
+ struct rpc_buffer *resp_buf = &req->response;
+ rpc_status = serializer->serialize_write_resp(resp_buf, num_written);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t erase_handler(void *context, struct rpc_request *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ struct rpc_buffer *req_buf = &req->request;
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ storage_partition_handle_t handle = 0;
+ uint64_t begin_lba = 0;
+ size_t num_blocks = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_erase_req(req_buf, &handle,
+ &begin_lba, &num_blocks);
+
+ if (rpc_status == RPC_SUCCESS) {
+
+ psa_status_t op_status = block_store_erase(
+ this_instance->block_store,
+ req->source_id,
+ handle,
+ begin_lba,
+ num_blocks);
+
+ req->service_status = op_status;
+ }
+
+ return rpc_status;
+}
diff --git a/components/service/block_storage/provider/block_storage_provider.h b/components/service/block_storage/provider/block_storage_provider.h
new file mode 100644
index 000000000..71f4e8ccd
--- /dev/null
+++ b/components/service/block_storage/provider/block_storage_provider.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BLOCK_STORAGE_PROVIDER_H
+#define BLOCK_STORAGE_PROVIDER_H
+
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "service/common/provider/service_provider.h"
+#include "service/block_storage/block_store/block_store.h"
+#include "serializer/block_storage_serializer.h"
+#include "protocols/rpc/common/packed-c/encoding.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* block_storage_provider service provider structure */
+struct block_storage_provider
+{
+ struct service_provider base_provider;
+ const struct block_storage_serializer *serializer;
+ struct block_store *block_store;
+};
+
+struct rpc_service_interface *block_storage_provider_init(
+ struct block_storage_provider *context,
+ struct block_store *block_store);
+
+void block_storage_provider_deinit(
+ struct block_storage_provider *context);
+
+void block_storage_provider_register_serializer(
+ struct block_storage_provider *context,
+ const struct block_storage_serializer *serializer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* BLOCK_STORAGE_PROVIDER_H */
diff --git a/components/service/block_storage/provider/block_storage_uuid.h b/components/service/block_storage/provider/block_storage_uuid.h
new file mode 100644
index 000000000..efda29eb2
--- /dev/null
+++ b/components/service/block_storage/provider/block_storage_uuid.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BLOCK_STORAGE_UUID_H
+#define BLOCK_STORAGE_UUID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TS_BLOCK_STORAGE_SERVICE_UUID \
+{ 0x63, 0x64, 0x6e, 0x80, 0xeb, 0x52, 0x46, 0x2f, 0xac, 0x4f, 0x8c, 0xdf, 0x39, 0x87, 0x51, 0x9c }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLOCK_STORAGE_UUID_H */
diff --git a/components/service/block_storage/provider/component.cmake b/components/service/block_storage/provider/component.cmake
new file mode 100644
index 000000000..23851f01e
--- /dev/null
+++ b/components/service/block_storage/provider/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_storage_provider.c"
+ )
diff --git a/components/service/block_storage/provider/serializer/block_storage_serializer.h b/components/service/block_storage/provider/serializer/block_storage_serializer.h
new file mode 100644
index 000000000..6aad6bfc2
--- /dev/null
+++ b/components/service/block_storage/provider/serializer/block_storage_serializer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BLOCK_STORAGE_PROVIDER_SERIALIZER_H
+#define BLOCK_STORAGE_PROVIDER_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "common/uuid/uuid.h"
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "service/block_storage/block_store/block_store.h"
+
+/* Provides a common interface for parameter serialization operations
+ * for the block storage service provider. Allows alternative serialization
+ * protocols to be used without hard-wiring a particular protocol
+ * into the service provider code. A concrete serializer must
+ * implement this interface.
+ */
+struct block_storage_serializer {
+
+ /* Operation: get_partition_info */
+ rpc_status_t (*deserialize_get_partition_info_req)(const struct rpc_buffer *req_buf,
+ struct uuid_octets *partition_guid);
+
+ rpc_status_t (*serialize_get_partition_info_resp)(struct rpc_buffer *resp_buf,
+ struct storage_partition_info *info);
+
+ /* Operation: open */
+ rpc_status_t (*deserialize_open_req)(const struct rpc_buffer *req_buf,
+ struct uuid_octets *partition_guid);
+
+ rpc_status_t (*serialize_open_resp)(struct rpc_buffer *resp_buf,
+ storage_partition_handle_t handle);
+
+ /* Operation: close */
+ rpc_status_t (*deserialize_close_req)(const struct rpc_buffer *req_buf,
+ storage_partition_handle_t *handle);
+
+ /* Operation: read */
+ rpc_status_t (*deserialize_read_req)(const struct rpc_buffer *req_buf,
+ storage_partition_handle_t *handle,
+ uint64_t *lba,
+ size_t *offset,
+ size_t *len);
+
+ /* Operation: write */
+ rpc_status_t (*deserialize_write_req)(const struct rpc_buffer *req_buf,
+ storage_partition_handle_t *handle,
+ uint64_t *lba,
+ size_t *offset,
+ const uint8_t **data,
+ size_t *data_len);
+
+ rpc_status_t (*serialize_write_resp)(struct rpc_buffer *resp_buf,
+ size_t num_written);
+
+ /* Operation: erase */
+ rpc_status_t (*deserialize_erase_req)(const struct rpc_buffer *req_buf,
+ storage_partition_handle_t *handle,
+ uint64_t *begin_lba,
+ size_t *num_blocks);
+};
+
+#endif /* BLOCK_STORAGE_PROVIDER_SERIALIZER_H */
diff --git a/components/service/block_storage/provider/serializer/packed-c/component.cmake b/components/service/block_storage/provider/serializer/packed-c/component.cmake
new file mode 100644
index 000000000..e5887a49f
--- /dev/null
+++ b/components/service/block_storage/provider/serializer/packed-c/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/packedc_block_storage_serializer.c"
+ )
diff --git a/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.c b/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.c
new file mode 100644
index 000000000..f11d574e1
--- /dev/null
+++ b/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+#include "common/tlv/tlv.h"
+#include "common/endian/le.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "protocols/service/block_storage/packed-c/messages.h"
+#include "packedc_block_storage_serializer.h"
+
+
+/* Operation: get_partition_info */
+rpc_status_t deserialize_get_partition_info_req(const struct rpc_buffer *req_buf,
+ struct uuid_octets *partition_guid)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_block_storage_get_partition_info_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_get_partition_info_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ memcpy(&partition_guid->octets, recv_msg.partition_guid, sizeof(partition_guid->octets));
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+rpc_status_t serialize_get_partition_info_resp(struct rpc_buffer *resp_buf,
+ struct storage_partition_info *info)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_block_storage_get_partition_info_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_block_storage_get_partition_info_out);
+
+ resp_msg.num_blocks = info->num_blocks;
+ resp_msg.block_size = info->block_size;
+
+ memcpy(resp_msg.partition_guid,
+ info->partition_guid.octets, TS_BLOCK_STORAGE_GUID_OCTET_LEN);
+
+ memcpy(resp_msg.parent_guid,
+ info->parent_guid.octets, TS_BLOCK_STORAGE_GUID_OCTET_LEN);
+
+ if (fixed_len <= resp_buf->size) {
+
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: open */
+rpc_status_t deserialize_open_req(const struct rpc_buffer *req_buf,
+ struct uuid_octets *partition_guid)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_block_storage_open_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_open_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ memcpy(&partition_guid->octets, recv_msg.partition_guid, sizeof(partition_guid->octets));
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+rpc_status_t serialize_open_resp(struct rpc_buffer *resp_buf,
+ storage_partition_handle_t handle)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_block_storage_open_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_block_storage_open_out);
+
+ resp_msg.handle = handle;
+
+ if (fixed_len <= resp_buf->size) {
+
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: close */
+rpc_status_t deserialize_close_req(const struct rpc_buffer *req_buf,
+ storage_partition_handle_t *handle)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_block_storage_close_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_close_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *handle = recv_msg.handle;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: read */
+rpc_status_t deserialize_read_req(const struct rpc_buffer *req_buf,
+ storage_partition_handle_t *handle,
+ uint64_t *lba,
+ size_t *offset,
+ size_t *len)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_block_storage_read_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_read_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *handle = recv_msg.handle;
+ *lba = recv_msg.lba;
+ *offset = recv_msg.offset;
+ *len = recv_msg.len;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: write */
+rpc_status_t deserialize_write_req(const struct rpc_buffer *req_buf,
+ storage_partition_handle_t *handle,
+ uint64_t *lba,
+ size_t *offset,
+ const uint8_t **data,
+ size_t *data_length)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_block_storage_write_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_write_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+ *handle = recv_msg.handle;
+ *lba = recv_msg.lba;
+ *offset = recv_msg.offset;
+
+ *data = (const uint8_t*)req_buf->data + expected_fixed_len;
+ *data_length = req_buf->data_length - expected_fixed_len;
+
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+rpc_status_t serialize_write_resp(struct rpc_buffer *resp_buf,
+ size_t num_written)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_block_storage_write_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_block_storage_write_out);
+
+ resp_msg.num_written = num_written;
+
+ if (fixed_len <= resp_buf->size) {
+
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: erase */
+rpc_status_t deserialize_erase_req(const struct rpc_buffer *req_buf,
+ storage_partition_handle_t *handle,
+ uint64_t *begin_lba,
+ size_t *num_blocks)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_block_storage_erase_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_erase_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+ *handle = recv_msg.handle;
+ *begin_lba = recv_msg.begin_lba;
+ *num_blocks = (size_t)recv_msg.num_blocks;
+
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Singleton method to provide access to the serializer instance */
+const struct block_storage_serializer *packedc_block_storage_serializer_instance(void)
+{
+ static const struct block_storage_serializer instance =
+ {
+ deserialize_get_partition_info_req,
+ serialize_get_partition_info_resp,
+ deserialize_open_req,
+ serialize_open_resp,
+ deserialize_close_req,
+ deserialize_read_req,
+ deserialize_write_req,
+ serialize_write_resp,
+ deserialize_erase_req
+ };
+
+ return &instance;
+}
diff --git a/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h b/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h
new file mode 100644
index 000000000..86c780797
--- /dev/null
+++ b/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_BLOCK_STORAGE_PROVIDER_SERIALIZER_H
+#define PACKEDC_BLOCK_STORAGE_PROVIDER_SERIALIZER_H
+
+#include <service/block_storage/provider/serializer/block_storage_serializer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Singleton method to provide access to the packed-c serializer
+ * for the block storage service provider.
+ */
+const struct block_storage_serializer *packedc_block_storage_serializer_instance(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PACKEDC_BLOCK_STORAGE_PROVIDER_SERIALIZER_H */
diff --git a/components/service/block_storage/test/service/block_storage_service_tests.cpp b/components/service/block_storage/test/service/block_storage_service_tests.cpp
new file mode 100644
index 000000000..4b256a5c3
--- /dev/null
+++ b/components/service/block_storage/test/service/block_storage_service_tests.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstring>
+#include "common/uuid/uuid.h"
+#include "service/block_storage/block_store/block_store.h"
+#include "service/block_storage/factory/client/block_store_factory.h"
+#include "service/block_storage/config/ref/ref_partition_configurator.h"
+#include "CppUTest/TestHarness.h"
+
+/**
+ * Service-level tests for the block storage service.
+ *
+ * Test cases assume that the backend block store has been configured using
+ * the reference configuration defined in ref_partition_configurator.c. This
+ * includes a set of partitions, identified by GUIDs referenced by these test
+ * cases.
+ */
+TEST_GROUP(BlockStorageServiceTests)
+{
+ void setup()
+ {
+ m_block_store = client_block_store_factory_create(
+ "sn:trustedfirmware.org:block-storage:0");
+
+ CHECK_TRUE(m_block_store);
+
+ uuid_guid_octets_from_canonical(&m_partition_1_guid,
+ REF_PARTITION_1_GUID);
+ uuid_guid_octets_from_canonical(&m_partition_2_guid,
+ REF_PARTITION_2_GUID);
+ uuid_guid_octets_from_canonical(&m_partition_3_guid,
+ REF_PARTITION_3_GUID);
+ uuid_guid_octets_from_canonical(&m_partition_4_guid,
+ REF_PARTITION_4_GUID);
+ }
+
+ void teardown()
+ {
+ client_block_store_factory_destroy(m_block_store);
+ }
+
+ static const uint32_t LOCAL_CLIENT_ID = 1;
+ static const uint32_t SECTOR_SIZE = 512;
+
+ struct block_store *m_block_store;
+ struct uuid_octets m_partition_1_guid;
+ struct uuid_octets m_partition_2_guid;
+ struct uuid_octets m_partition_3_guid;
+ struct uuid_octets m_partition_4_guid;
+};
+
+TEST(BlockStorageServiceTests, getPartitionInfo)
+{
+ struct storage_partition_info info;
+
+ /* Check partition info for partition 1 */
+ psa_status_t status = block_store_get_partition_info(
+ m_block_store, &m_partition_1_guid, &info);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ LONGS_EQUAL(REF_PARTITION_1_ENDING_LBA - REF_PARTITION_1_STARTING_LBA + 1,
+ info.num_blocks * info.block_size / SECTOR_SIZE);
+ LONGS_EQUAL(REF_PARTITION_BLOCK_SIZE, info.block_size);
+ MEMCMP_EQUAL(m_partition_1_guid.octets,
+ info.partition_guid.octets, sizeof(info.partition_guid.octets));
+
+ /* Check partition info for partition 2 */
+ status = block_store_get_partition_info(
+ m_block_store, &m_partition_2_guid, &info);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ LONGS_EQUAL(REF_PARTITION_2_ENDING_LBA - REF_PARTITION_2_STARTING_LBA + 1,
+ info.num_blocks * info.block_size / SECTOR_SIZE);
+ LONGS_EQUAL(REF_PARTITION_BLOCK_SIZE, info.block_size);
+ MEMCMP_EQUAL(m_partition_2_guid.octets,
+ info.partition_guid.octets, sizeof(info.partition_guid.octets));
+
+ /* Check partition info for partition 3 */
+ status = block_store_get_partition_info(
+ m_block_store, &m_partition_3_guid, &info);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ LONGS_EQUAL(REF_PARTITION_3_ENDING_LBA - REF_PARTITION_3_STARTING_LBA + 1,
+ info.num_blocks * info.block_size / SECTOR_SIZE);
+ LONGS_EQUAL(REF_PARTITION_BLOCK_SIZE, info.block_size);
+ MEMCMP_EQUAL(m_partition_3_guid.octets,
+ info.partition_guid.octets, sizeof(info.partition_guid.octets));
+
+ /* Check partition info for partition 4 */
+ status = block_store_get_partition_info(
+ m_block_store, &m_partition_4_guid, &info);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ LONGS_EQUAL(REF_PARTITION_4_ENDING_LBA - REF_PARTITION_4_STARTING_LBA + 1,
+ info.num_blocks * info.block_size / SECTOR_SIZE);
+ LONGS_EQUAL(REF_PARTITION_BLOCK_SIZE, info.block_size);
+ MEMCMP_EQUAL(m_partition_4_guid.octets,
+ info.partition_guid.octets, sizeof(info.partition_guid.octets));
+}
+
+TEST(BlockStorageServiceTests, openClose)
+{
+ storage_partition_handle_t handle_1;
+ storage_partition_handle_t handle_2;
+ storage_partition_handle_t handle_3;
+ storage_partition_handle_t handle_4;
+
+ /* Open all reference partitions */
+ psa_status_t status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_1_guid, &handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_2_guid, &handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_3_guid, &handle_3);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_4_guid, &handle_4);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Close them all */
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_1);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_2);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_3);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle_4);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
+
+TEST(BlockStorageServiceTests, blockAccessOperations)
+{
+ storage_partition_handle_t handle;
+ uint8_t write_buffer[REF_PARTITION_BLOCK_SIZE];
+ uint8_t read_buffer[REF_PARTITION_BLOCK_SIZE];
+ struct storage_partition_info info;
+ size_t num_written = 0;
+
+ /* Get info about one of the partitions */
+ psa_status_t status = block_store_get_partition_info(
+ m_block_store, &m_partition_3_guid, &info);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Open a partition */
+ status = block_store_open(
+ m_block_store, LOCAL_CLIENT_ID, &m_partition_3_guid, &handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Write over the entire partition */
+ for (uint64_t lba = 0; lba < info.num_blocks; ++lba) {
+
+ memset(write_buffer, lba & 0xff, sizeof(write_buffer));
+
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle, lba,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), num_written);
+ }
+
+ /* Expect to read the same data back */
+ for (uint64_t lba = 0; lba < info.num_blocks; ++lba) {
+
+ size_t data_len;
+
+ memset(write_buffer, lba & 0xff, sizeof(write_buffer));
+ memset(read_buffer, 0, sizeof(read_buffer));
+
+ status = block_store_read(
+ m_block_store, LOCAL_CLIENT_ID, handle, lba,
+ 0, sizeof(read_buffer), read_buffer, &data_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), data_len);
+ MEMCMP_EQUAL(write_buffer, read_buffer, sizeof(write_buffer));
+ }
+
+ /* Erase a set of blocks */
+ uint64_t erase_begin_lba = 0;
+ size_t erase_len = 3;
+ status = block_store_erase(
+ m_block_store, LOCAL_CLIENT_ID, handle,
+ erase_begin_lba, erase_len);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+
+ /* Write over the erased blocks - this should now work */
+ for (uint64_t lba = erase_begin_lba; lba < erase_len; ++lba) {
+
+ memset(write_buffer, lba & 0xff, sizeof(write_buffer));
+
+ status = block_store_write(
+ m_block_store, LOCAL_CLIENT_ID, handle, lba,
+ 0, write_buffer, sizeof(write_buffer), &num_written);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(sizeof(write_buffer), num_written);
+ }
+
+ /* Expect to successfully close the partition*/
+ status = block_store_close(m_block_store, LOCAL_CLIENT_ID, handle);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+}
diff --git a/components/service/block_storage/test/service/component.cmake b/components/service/block_storage/test/service/component.cmake
new file mode 100644
index 000000000..5d9f8bc36
--- /dev/null
+++ b/components/service/block_storage/test/service/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_storage_service_tests.cpp"
+ )
diff --git a/components/service/common/client/service_client.c b/components/service/common/client/service_client.c
index d5e87356f..109c9097d 100644
--- a/components/service/common/client/service_client.c
+++ b/components/service/common/client/service_client.c
@@ -4,32 +4,31 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <stddef.h>
-#include <protocols/rpc/common/packed-c/status.h>
#include "service_client.h"
+#include <stddef.h>
-psa_status_t service_client_init(
- struct service_client *context,
- struct rpc_caller *caller)
+psa_status_t service_client_init(struct service_client *context,
+ struct rpc_caller_session *session)
{
- context->caller = caller;
- context->rpc_status = TS_RPC_CALL_ACCEPTED;
+ if (!context || !session)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ context->session = session;
+ context->rpc_status = RPC_SUCCESS;
context->service_info.supported_encodings = 0;
- context->service_info.max_payload = 0;
+ context->service_info.max_payload = 4096;
return PSA_SUCCESS;
}
-void service_client_deinit(
- struct service_client *context)
+void service_client_deinit(struct service_client *context)
{
- context->caller = NULL;
+ context->session = NULL;
}
-void service_client_set_service_info(
- struct service_client *context,
- const struct service_info *service_info)
+void service_client_set_service_info(struct service_client *context,
+ const struct service_info *service_info)
{
context->service_info = *service_info;
}
diff --git a/components/service/common/client/service_client.h b/components/service/common/client/service_client.h
index df5b31bcf..70a6aee8a 100644
--- a/components/service/common/client/service_client.h
+++ b/components/service/common/client/service_client.h
@@ -9,7 +9,7 @@
#include <stddef.h>
#include <psa/error.h>
-#include <rpc_caller.h>
+#include "components/rpc/common/caller/rpc_caller_session.h"
#include <service/common/client/service_info.h>
#ifdef __cplusplus
@@ -23,11 +23,11 @@ extern "C" {
* Includes common information about the service that will have been discovered
* in some way. The TS discovery protocol provides a way to do this. If
* service info is not available, the service_info structure stays in its
- * initialied state.
+ * initialised state.
*/
struct service_client
{
- struct rpc_caller *caller;
+ struct rpc_caller_session *session;
int rpc_status;
struct service_info service_info;
};
@@ -45,7 +45,7 @@ struct service_client
*/
psa_status_t service_client_init(
struct service_client *context,
- struct rpc_caller *caller);
+ struct rpc_caller_session *session);
/**
* @brief De-initialises the service client
diff --git a/components/service/common/include/psa/client.h b/components/service/common/include/psa/client.h
new file mode 100644
index 000000000..db40d7afe
--- /dev/null
+++ b/components/service/common/include/psa/client.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2018-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SERVICE_PSA_IPC_H
+#define SERVICE_PSA_IPC_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <rpc_caller.h>
+#include <psa/error.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef IOVEC_LEN
+#define IOVEC_LEN(arr) ((uint32_t)(sizeof(arr)/sizeof(arr[0])))
+#endif
+
+/*********************** PSA Client Macros and Types *************************/
+
+typedef int32_t psa_handle_t;
+
+/**
+ * The version of the PSA Framework API that is being used to build the calling
+ * firmware. Only part of features of FF-M v1.1 have been implemented. FF-M v1.1
+ * is compatible with v1.0.
+ */
+#define PSA_FRAMEWORK_VERSION (0x0101u)
+
+/**
+ * Return value from psa_version() if the requested RoT Service is not present
+ * in the system.
+ */
+#define PSA_VERSION_NONE (0u)
+
+/**
+ * The zero-value null handle can be assigned to variables used in clients and
+ * RoT Services, indicating that there is no current connection or message.
+ */
+#define PSA_NULL_HANDLE ((psa_handle_t)0)
+
+/**
+ * Tests whether a handle value returned by psa_connect() is valid.
+ */
+#define PSA_HANDLE_IS_VALID(handle) ((psa_handle_t)(handle) > 0)
+
+/**
+ * Converts the handle value returned from a failed call psa_connect() into
+ * an error code.
+ */
+#define PSA_HANDLE_TO_ERROR(handle) ((psa_status_t)(handle))
+
+/**
+ * Maximum number of input and output vectors for a request to psa_call().
+ */
+#define PSA_MAX_IOVEC (4u)
+
+/**
+ * An IPC message type that indicates a generic client request.
+ */
+#define PSA_IPC_CALL (0)
+
+/**
+ * A read-only input memory region provided to an RoT Service.
+ */
+struct __attribute__ ((__packed__)) psa_invec {
+ uint32_t base; /*!< the start address of the memory buffer */
+ uint32_t len; /*!< the size in bytes */
+};
+
+/**
+ * A writable output memory region provided to an RoT Service.
+ */
+struct __attribute__ ((__packed__)) psa_outvec {
+ uint32_t base; /*!< the start address of the memory buffer */
+ uint32_t len; /*!< the size in bytes */
+};
+
+inline static void *psa_u32_to_ptr(uint32_t addr)
+{
+ return (void *)(uintptr_t)addr;
+}
+
+inline static uint32_t psa_ptr_to_u32(void *ptr)
+{
+ return (uintptr_t)ptr;
+}
+
+inline static uint32_t psa_ptr_const_to_u32(const void *ptr)
+{
+ return (uintptr_t)ptr;
+}
+
+/*************************** PSA Client API **********************************/
+
+/**
+ * \brief Retrieve the version of the PSA Framework API that is implemented.
+ *
+ * \param[in] rpc_caller RPC caller to use
+ * \return version The version of the PSA Framework implementation
+ * that is providing the runtime services to the
+ * caller. The major and minor version are encoded
+ * as follows:
+ * \arg version[15:8] -- major version number.
+ * \arg version[7:0] -- minor version number.
+ */
+uint32_t psa_framework_version(struct rpc_caller_interface *caller);
+
+/**
+ * \brief Retrieve the version of an RoT Service or indicate that it is not
+ * present on this system.
+ *
+ * \param[in] rpc_caller RPC caller to use
+ * \param[in] sid ID of the RoT Service to query.
+ *
+ * \retval PSA_VERSION_NONE The RoT Service is not implemented, or the
+ * caller is not permitted to access the service.
+ * \retval > 0 The version of the implemented RoT Service.
+ */
+uint32_t psa_version(struct rpc_caller_interface *caller, uint32_t sid);
+
+/**
+ * \brief Connect to an RoT Service by its SID.
+ *
+ * \param[in] rpc_caller RPC caller to use
+ * \param[in] sid ID of the RoT Service to connect to.
+ * \param[in] version Requested version of the RoT Service.
+ *
+ * \retval > 0 A handle for the connection.
+ * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
+ * connection.
+ * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
+ * connection at the moment.
+ * \retval "PROGRAMMER ERROR" The call is a PROGRAMMER ERROR if one or more
+ * of the following are true:
+ * \arg The RoT Service ID is not present.
+ * \arg The RoT Service version is not supported.
+ * \arg The caller is not allowed to access the RoT
+ * service.
+ */
+psa_handle_t psa_connect(struct rpc_caller_interface *caller, uint32_t sid,
+ uint32_t version);
+
+/**
+ * \brief Call an RoT Service on an established connection.
+ *
+ * \note FF-M 1.0 proposes 6 parameters for psa_call but the secure gateway ABI
+ * support at most 4 parameters. TF-M chooses to encode 'in_len',
+ * 'out_len', and 'type' into a 32-bit integer to improve efficiency.
+ * Compared with struct-based encoding, this method saves extra memory
+ * check and memory copy operation. The disadvantage is that the 'type'
+ * range has to be reduced into a 16-bit integer. So with this encoding,
+ * the valid range for 'type' is 0-32767.
+ *
+ * \param[in] rpc_caller RPC caller to use
+ * \param[in] handle A handle to an established connection.
+ * \param[in] type The request type.
+ * Must be zero( \ref PSA_IPC_CALL) or positive.
+ * \param[in] in_vec Array of input \ref psa_invec structures.
+ * \param[in] in_len Number of input \ref psa_invec structures.
+ * \param[in,out] out_vec Array of output \ref psa_outvec structures.
+ * \param[in] out_len Number of output \ref psa_outvec structures.
+ *
+ * \retval >=0 RoT Service-specific status value.
+ * \retval <0 RoT Service-specific error code.
+ * \retval PSA_ERROR_PROGRAMMER_ERROR The connection has been terminated by the
+ * RoT Service. The call is a PROGRAMMER ERROR if
+ * one or more of the following are true:
+ * \arg An invalid handle was passed.
+ * \arg The connection is already handling a request.
+ * \arg type < 0.
+ * \arg An invalid memory reference was provided.
+ * \arg in_len + out_len > PSA_MAX_IOVEC.
+ * \arg The message is unrecognized by the RoT
+ * Service or incorrectly formatted.
+ */
+psa_status_t psa_call(struct rpc_caller_interface *caller, psa_handle_t handle,
+ int32_t type, const struct psa_invec *in_vec,
+ size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Call an RoT Service on an established connection.
+ *
+ * \note FF-M 1.0 proposes 6 parameters for psa_call but the secure gateway ABI
+ * support at most 4 parameters. TF-M chooses to encode 'in_len',
+ * 'out_len', and 'type' into a 32-bit integer to improve efficiency.
+ * Compared with struct-based encoding, this method saves extra memory
+ * check and memory copy operation. The disadvantage is that the 'type'
+ * range has to be reduced into a 16-bit integer. So with this encoding,
+ * the valid range for 'type' is 0-32767.
+ *
+ * \param[in] rpc_caller RPC caller to use
+ * \param[in] handle A handle to an established connection.
+ * \param[in] client_id A client_id to be passed over the request
+ * \param[in] type The request type.
+ * Must be zero( \ref PSA_IPC_CALL) or positive.
+ * \param[in] in_vec Array of input \ref psa_invec structures.
+ * \param[in] in_len Number of input \ref psa_invec structures.
+ * \param[in,out] out_vec Array of output \ref psa_outvec structures.
+ * \param[in] out_len Number of output \ref psa_outvec structures.
+ *
+ * \retval >=0 RoT Service-specific status value.
+ * \retval <0 RoT Service-specific error code.
+ * \retval PSA_ERROR_PROGRAMMER_ERROR The connection has been terminated by the
+ * RoT Service. The call is a PROGRAMMER ERROR if
+ * one or more of the following are true:
+ * \arg An invalid handle was passed.
+ * \arg The connection is already handling a request.
+ * \arg type < 0.
+ * \arg An invalid memory reference was provided.
+ * \arg in_len + out_len > PSA_MAX_IOVEC.
+ * \arg The message is unrecognized by the RoT
+ * Service or incorrectly formatted.
+ */
+psa_status_t psa_call_client_id(struct rpc_caller_interface *caller, psa_handle_t handle,
+ int32_t client_id, int32_t type,
+ const struct psa_invec *in_vec, size_t in_len,
+ struct psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Close a connection to an RoT Service.
+ *
+ * \param[in] rpc_caller RPC caller to use
+ * \param[in] handle A handle to an established connection, or the
+ * null handle.
+ *
+ * \retval void Success.
+ * \retval "PROGRAMMER ERROR" The call is a PROGRAMMER ERROR if one or more
+ * of the following are true:
+ * \arg An invalid handle was provided that is not
+ * the null handle.
+ * \arg The connection is currently handling a
+ * request.
+ */
+void psa_close(struct rpc_caller_interface *caller, psa_handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERVICE_PSA_IPC_H */
+
+
diff --git a/components/service/common/include/psa/crypto_sid.h b/components/service/common/include/psa/crypto_sid.h
new file mode 100644
index 000000000..5b05f46d7
--- /dev/null
+++ b/components/service/common/include/psa/crypto_sid.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __PSA_CRYPTO_SID_H__
+#define __PSA_CRYPTO_SID_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <stdint.h>
+
+/**
+ * \brief Type associated to the group of a function encoding. There can be
+ * nine groups (Random, Key management, Hash, MAC, Cipher, AEAD,
+ * Asym sign, Asym encrypt, Key derivation).
+ */
+enum tfm_crypto_group_id {
+ TFM_CRYPTO_GROUP_ID_RANDOM = 0x0,
+ TFM_CRYPTO_GROUP_ID_KEY_MANAGEMENT,
+ TFM_CRYPTO_GROUP_ID_HASH,
+ TFM_CRYPTO_GROUP_ID_MAC,
+ TFM_CRYPTO_GROUP_ID_CIPHER,
+ TFM_CRYPTO_GROUP_ID_AEAD,
+ TFM_CRYPTO_GROUP_ID_ASYM_SIGN,
+ TFM_CRYPTO_GROUP_ID_ASYM_ENCRYPT,
+ TFM_CRYPTO_GROUP_ID_KEY_DERIVATION,
+};
+
+/* X macro describing each of the available PSA Crypto APIs */
+#define KEY_MANAGEMENT_FUNCS \
+ X(TFM_CRYPTO_GET_KEY_ATTRIBUTES) \
+ X(TFM_CRYPTO_RESET_KEY_ATTRIBUTES) \
+ X(TFM_CRYPTO_OPEN_KEY) \
+ X(TFM_CRYPTO_CLOSE_KEY) \
+ X(TFM_CRYPTO_IMPORT_KEY) \
+ X(TFM_CRYPTO_DESTROY_KEY) \
+ X(TFM_CRYPTO_EXPORT_KEY) \
+ X(TFM_CRYPTO_EXPORT_PUBLIC_KEY) \
+ X(TFM_CRYPTO_PURGE_KEY) \
+ X(TFM_CRYPTO_COPY_KEY) \
+ X(TFM_CRYPTO_GENERATE_KEY)
+
+#define HASH_FUNCS \
+ X(TFM_CRYPTO_HASH_COMPUTE) \
+ X(TFM_CRYPTO_HASH_COMPARE) \
+ X(TFM_CRYPTO_HASH_SETUP) \
+ X(TFM_CRYPTO_HASH_UPDATE) \
+ X(TFM_CRYPTO_HASH_CLONE) \
+ X(TFM_CRYPTO_HASH_FINISH) \
+ X(TFM_CRYPTO_HASH_VERIFY) \
+ X(TFM_CRYPTO_HASH_ABORT)
+
+#define MAC_FUNCS \
+ X(TFM_CRYPTO_MAC_COMPUTE) \
+ X(TFM_CRYPTO_MAC_VERIFY) \
+ X(TFM_CRYPTO_MAC_SIGN_SETUP) \
+ X(TFM_CRYPTO_MAC_VERIFY_SETUP) \
+ X(TFM_CRYPTO_MAC_UPDATE) \
+ X(TFM_CRYPTO_MAC_SIGN_FINISH) \
+ X(TFM_CRYPTO_MAC_VERIFY_FINISH) \
+ X(TFM_CRYPTO_MAC_ABORT)
+
+#define CIPHER_FUNCS \
+ X(TFM_CRYPTO_CIPHER_ENCRYPT) \
+ X(TFM_CRYPTO_CIPHER_DECRYPT) \
+ X(TFM_CRYPTO_CIPHER_ENCRYPT_SETUP) \
+ X(TFM_CRYPTO_CIPHER_DECRYPT_SETUP) \
+ X(TFM_CRYPTO_CIPHER_GENERATE_IV) \
+ X(TFM_CRYPTO_CIPHER_SET_IV) \
+ X(TFM_CRYPTO_CIPHER_UPDATE) \
+ X(TFM_CRYPTO_CIPHER_FINISH) \
+ X(TFM_CRYPTO_CIPHER_ABORT)
+
+#define AEAD_FUNCS \
+ X(TFM_CRYPTO_AEAD_ENCRYPT) \
+ X(TFM_CRYPTO_AEAD_DECRYPT) \
+ X(TFM_CRYPTO_AEAD_ENCRYPT_SETUP) \
+ X(TFM_CRYPTO_AEAD_DECRYPT_SETUP) \
+ X(TFM_CRYPTO_AEAD_GENERATE_NONCE) \
+ X(TFM_CRYPTO_AEAD_SET_NONCE) \
+ X(TFM_CRYPTO_AEAD_SET_LENGTHS) \
+ X(TFM_CRYPTO_AEAD_UPDATE_AD) \
+ X(TFM_CRYPTO_AEAD_UPDATE) \
+ X(TFM_CRYPTO_AEAD_FINISH) \
+ X(TFM_CRYPTO_AEAD_VERIFY) \
+ X(TFM_CRYPTO_AEAD_ABORT)
+
+#define ASYMMETRIC_SIGN_FUNCS \
+ X(TFM_CRYPTO_ASYMMETRIC_SIGN_MESSAGE) \
+ X(TFM_CRYPTO_ASYMMETRIC_VERIFY_MESSAGE) \
+ X(TFM_CRYPTO_ASYMMETRIC_SIGN_HASH) \
+ X(TFM_CRYPTO_ASYMMETRIC_VERIFY_HASH)
+
+#define AYSMMETRIC_ENCRYPT_FUNCS \
+ X(TFM_CRYPTO_ASYMMETRIC_ENCRYPT) \
+ X(TFM_CRYPTO_ASYMMETRIC_DECRYPT)
+
+#define KEY_DERIVATION_FUNCS \
+ X(TFM_CRYPTO_RAW_KEY_AGREEMENT) \
+ X(TFM_CRYPTO_KEY_DERIVATION_SETUP) \
+ X(TFM_CRYPTO_KEY_DERIVATION_GET_CAPACITY) \
+ X(TFM_CRYPTO_KEY_DERIVATION_SET_CAPACITY) \
+ X(TFM_CRYPTO_KEY_DERIVATION_INPUT_BYTES) \
+ X(TFM_CRYPTO_KEY_DERIVATION_INPUT_KEY) \
+ X(TFM_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT) \
+ X(TFM_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES) \
+ X(TFM_CRYPTO_KEY_DERIVATION_OUTPUT_KEY) \
+ X(TFM_CRYPTO_KEY_DERIVATION_ABORT)
+
+#define RANDOM_FUNCS \
+ X(TFM_CRYPTO_GENERATE_RANDOM)
+
+/*
+ * Define function IDs in each group. The function ID will be encoded into
+ * tfm_crypto_func_sid below.
+ * Each group is defined as a dedicated enum in case the total number of
+ * PSA Crypto APIs exceeds 256.
+ */
+#define X(func_id) func_id,
+enum tfm_crypto_key_management_func_id {
+ KEY_MANAGEMENT_FUNCS
+};
+enum tfm_crypto_hash_func_id {
+ HASH_FUNCS
+};
+enum tfm_crypto_mac_func_id {
+ MAC_FUNCS
+};
+enum tfm_crypto_cipher_func_id {
+ CIPHER_FUNCS
+};
+enum tfm_crypto_aead_func_id {
+ AEAD_FUNCS
+};
+enum tfm_crypto_asym_sign_func_id {
+ ASYMMETRIC_SIGN_FUNCS
+};
+enum tfm_crypto_asym_encrypt_func_id {
+ AYSMMETRIC_ENCRYPT_FUNCS
+};
+enum tfm_crypto_key_derivation_func_id {
+ KEY_DERIVATION_FUNCS
+};
+enum tfm_crypto_random_func_id {
+ RANDOM_FUNCS
+};
+#undef X
+
+#define FUNC_ID(func_id) (((func_id) & 0xFF) << 8)
+
+/*
+ * Numerical progressive value identifying a function API exposed through
+ * the interfaces (S or NS). It's used to dispatch the requests from S/NS
+ * to the corresponding API implementation in the Crypto service backend.
+ *
+ * Each function SID is encoded as uint16_t.
+ * | Func ID | Group ID |
+ * 15 8 7 0
+ * Func ID is defined in each group func_id enum above
+ * Group ID is defined in tfm_crypto_group_id.
+ */
+enum tfm_crypto_func_sid {
+
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_KEY_MANAGEMENT & 0xFF)),
+
+ KEY_MANAGEMENT_FUNCS
+
+#undef X
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_HASH & 0xFF)),
+ HASH_FUNCS
+
+#undef X
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_MAC & 0xFF)),
+ MAC_FUNCS
+
+#undef X
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_CIPHER & 0xFF)),
+ CIPHER_FUNCS
+
+#undef X
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_AEAD & 0xFF)),
+ AEAD_FUNCS
+
+#undef X
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_ASYM_SIGN & 0xFF)),
+ ASYMMETRIC_SIGN_FUNCS
+
+#undef X
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_ASYM_ENCRYPT & 0xFF)),
+ AYSMMETRIC_ENCRYPT_FUNCS
+
+#undef X
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_KEY_DERIVATION & 0xFF)),
+ KEY_DERIVATION_FUNCS
+
+#undef X
+#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \
+ (TFM_CRYPTO_GROUP_ID_RANDOM & 0xFF)),
+ RANDOM_FUNCS
+
+};
+#undef X
+
+/**
+ * \brief Define an invalid value for an SID
+ *
+ */
+#define TFM_CRYPTO_SID_INVALID (~0x0u)
+
+/**
+ * \brief This value is used to mark an handle as invalid.
+ *
+ */
+#define TFM_CRYPTO_INVALID_HANDLE (0x0u)
+
+/**
+ * \brief Define miscellaneous literal constants that are used in the service
+ *
+ */
+enum {
+ TFM_CRYPTO_NOT_IN_USE = 0,
+ TFM_CRYPTO_IN_USE = 1
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_CRYPTO_SID_H__ */
diff --git a/components/service/common/include/psa/sid.h b/components/service/common/include/psa/sid.h
new file mode 100644
index 000000000..5aaa659d4
--- /dev/null
+++ b/components/service/common/include/psa/sid.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __PSA_MANIFEST_SID_H__
+#define __PSA_MANIFEST_SID_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******** PSA Crypto SIDs ********/
+#include "crypto_sid.h"
+
+/******** TFM_SP_PS ********/
+#define TFM_PROTECTED_STORAGE_SERVICE_SID (0x00000060U)
+#define TFM_PROTECTED_STORAGE_SERVICE_VERSION (1U)
+#define TFM_PROTECTED_STORAGE_SERVICE_HANDLE (0x40000101U)
+
+/* Invalid UID */
+#define TFM_PS_INVALID_UID 0
+
+/* PS / ITS message types that distinguish PS services. */
+#define TFM_PS_ITS_SET 1001
+#define TFM_PS_ITS_GET 1002
+#define TFM_PS_ITS_GET_INFO 1003
+#define TFM_PS_ITS_REMOVE 1004
+#define TFM_PS_ITS_GET_SUPPORT 1005
+
+/******** TFM_SP_ITS ********/
+#define TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_SID (0x00000070U)
+#define TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_VERSION (1U)
+#define TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_HANDLE (0x40000102U)
+
+/******** TFM_SP_CRYPTO ********/
+#define TFM_CRYPTO_SID (0x00000080U)
+#define TFM_CRYPTO_VERSION (1U)
+#define TFM_CRYPTO_HANDLE (0x40000100U)
+
+/******** TFM_SP_PLATFORM ********/
+#define TFM_SP_PLATFORM_SYSTEM_RESET_SID (0x00000040U)
+#define TFM_SP_PLATFORM_SYSTEM_RESET_VERSION (1U)
+#define TFM_SP_PLATFORM_IOCTL_SID (0x00000041U)
+#define TFM_SP_PLATFORM_IOCTL_VERSION (1U)
+#define TFM_SP_PLATFORM_NV_COUNTER_SID (0x00000042U)
+#define TFM_SP_PLATFORM_NV_COUNTER_VERSION (1U)
+
+/******** TFM_SP_INITIAL_ATTESTATION ********/
+#define TFM_ATTESTATION_SERVICE_SID (0x00000020U)
+#define TFM_ATTESTATION_SERVICE_VERSION (1U)
+#define TFM_ATTESTATION_SERVICE_HANDLE (0x40000103U)
+
+/* Initial Attestation message types that distinguish Attest services. */
+#define TFM_ATTEST_GET_TOKEN 1001
+#define TFM_ATTEST_GET_TOKEN_SIZE 1002
+
+/******** TFM_SP_FWU ********/
+#define TFM_FWU_WRITE_SID (0x000000A0U)
+#define TFM_FWU_WRITE_VERSION (1U)
+#define TFM_FWU_INSTALL_SID (0x000000A1U)
+#define TFM_FWU_INSTALL_VERSION (1U)
+#define TFM_FWU_ABORT_SID (0x000000A2U)
+#define TFM_FWU_ABORT_VERSION (1U)
+#define TFM_FWU_QUERY_SID (0x000000A3U)
+#define TFM_FWU_QUERY_VERSION (1U)
+#define TFM_FWU_REQUEST_REBOOT_SID (0x000000A4U)
+#define TFM_FWU_REQUEST_REBOOT_VERSION (1U)
+#define TFM_FWU_ACCEPT_SID (0x000000A5U)
+#define TFM_FWU_ACCEPT_VERSION (1U)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_SID_H__ */
diff --git a/components/service/common/provider/service_provider.c b/components/service/common/provider/service_provider.c
index e2f21da5e..b6fbe3d83 100644
--- a/components/service/common/provider/service_provider.c
+++ b/components/service/common/provider/service_provider.c
@@ -7,14 +7,14 @@
#include "service_provider.h"
#include <protocols/rpc/common/packed-c/status.h>
#include <stddef.h>
+#include <string.h>
static const struct service_handler *find_handler(const struct service_provider *sp,
- uint32_t opcode)
+ uint32_t opcode)
{
const struct service_handler *handler = NULL;
if ((opcode >= sp->opcode_range_lo) && (opcode <= sp->opcode_range_hi)) {
-
size_t index = 0;
while (index < sp->num_handlers) {
@@ -40,7 +40,6 @@ static void set_opcode_range(struct service_provider *sp)
* providers are chained.
*/
for (size_t index = 0; index < sp->num_handlers; index++) {
-
uint32_t opcode = service_handler_get_opcode(&sp->handlers[index]);
if (opcode < lo) lo = opcode;
@@ -51,37 +50,35 @@ static void set_opcode_range(struct service_provider *sp)
sp->opcode_range_hi = hi;
}
-static rpc_status_t receive(struct rpc_interface *rpc_iface, struct call_req *req)
+static rpc_status_t receive(void *context, struct rpc_request *req)
{
+ struct rpc_service_interface *rpc_iface = (struct rpc_service_interface *)context;
rpc_status_t rpc_status;
struct service_provider *sp = NULL;
const struct service_handler *handler = NULL;
sp = (struct service_provider*)((char*)rpc_iface - offsetof(struct service_provider, iface));
- handler = find_handler(sp, call_req_get_opcode(req));
+ handler = find_handler(sp, req->opcode);
if (handler) {
-
- rpc_status = service_handler_invoke(handler, rpc_iface->context, req);
- }
- else if (sp->successor) {
-
- rpc_status = rpc_interface_receive(sp->successor, req);
- }
- else {
-
- rpc_status = TS_RPC_ERROR_INVALID_OPCODE;
+ rpc_status = service_handler_invoke(handler, rpc_iface->context, req);
+ } else if (sp->successor) {
+ rpc_status = rpc_service_receive(sp->successor, req);
+ } else {
+ rpc_status = RPC_ERROR_INVALID_VALUE;
}
return rpc_status;
}
void service_provider_init(struct service_provider *sp, void *context,
- const struct service_handler *handlers,
- size_t num_handlers)
+ const struct rpc_uuid *service_uuid,
+ const struct service_handler *handlers,
+ size_t num_handlers)
{
sp->iface.receive = receive;
sp->iface.context = context;
+ memcpy(&sp->iface.uuid, service_uuid, sizeof(sp->iface.uuid));
sp->handlers = handlers;
sp->num_handlers = num_handlers;
@@ -92,7 +89,7 @@ void service_provider_init(struct service_provider *sp, void *context,
}
void service_provider_extend(struct service_provider *context,
- struct service_provider *sub_provider)
+ struct service_provider *sub_provider)
{
sub_provider->successor = context->successor;
context->successor = &sub_provider->iface;
diff --git a/components/service/common/provider/service_provider.h b/components/service/common/provider/service_provider.h
index a0e853e2e..c64adb926 100644
--- a/components/service/common/provider/service_provider.h
+++ b/components/service/common/provider/service_provider.h
@@ -7,7 +7,7 @@
#ifndef SERVICE_PROVIDER_H
#define SERVICE_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "rpc/common/endpoint/rpc_service_interface.h"
#include <stddef.h>
#include <stdint.h>
@@ -22,11 +22,11 @@ extern "C" {
*/
struct service_handler {
uint32_t opcode;
- rpc_status_t (*invoke)(void *context, struct call_req* req);
+ rpc_status_t (*invoke)(void *context, struct rpc_request *req);
};
-static inline int service_handler_invoke(const struct service_handler *handler,
- void *context, struct call_req* req)
+static inline int service_handler_invoke(const struct service_handler *handler, void *context,
+ struct rpc_request *req)
{
return handler->invoke(context, req);
}
@@ -39,27 +39,27 @@ static inline uint32_t service_handler_get_opcode(const struct service_handler *
/** \brief Service provider
*
* A generalised service provider that acts as an rpc call endpoint. It receives call
- * requests and delegates them to the approprate handle provided by a concrete service
+ * requests and delegates them to the appropriate handle provided by a concrete service
* provider. To support service specialization and proxying, unhandled requests may
* optionally be passed to a delegate rpc_interface to form a chain of responsibility.
*/
struct service_provider {
- struct rpc_interface iface;
+ struct rpc_service_interface iface;
const struct service_handler *handlers;
size_t num_handlers;
uint32_t opcode_range_lo;
uint32_t opcode_range_hi;
- struct rpc_interface *successor;
+ struct rpc_service_interface *successor;
};
-static inline struct rpc_interface *service_provider_get_rpc_interface(struct service_provider *sp)
+static inline struct rpc_service_interface *service_provider_get_rpc_interface(struct service_provider *sp)
{
return &sp->iface;
}
void service_provider_init(struct service_provider *sp, void *context,
- const struct service_handler *handlers,
- size_t num_handlers);
+ const struct rpc_uuid *service_uuid,
+ const struct service_handler *handlers, size_t num_handlers);
/*
* Extend the core set of operations provided by a service provider by
@@ -69,7 +69,7 @@ void service_provider_init(struct service_provider *sp, void *context,
* provider if needed.
*/
void service_provider_extend(struct service_provider *context,
- struct service_provider *sub_provider);
+ struct service_provider *sub_provider);
/*
* Link a successor to this service provider to extend the chain of responsibility
@@ -77,7 +77,7 @@ void service_provider_extend(struct service_provider *context,
* modular configuration of service capabilities.
*/
static inline void service_provider_link_successor(struct service_provider *sp,
- struct rpc_interface *successor)
+ struct rpc_service_interface *successor)
{
sp->successor = successor;
}
diff --git a/components/service/common/provider/test/service_framework_tests.cpp b/components/service/common/provider/test/service_framework_tests.cpp
index e4afb18bd..568f9c608 100644
--- a/components/service/common/provider/test/service_framework_tests.cpp
+++ b/components/service/common/provider/test/service_framework_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,46 +9,49 @@
#include <service/common/provider/service_provider.h>
#include <protocols/rpc/common/packed-c/status.h>
#include <rpc/direct/direct_caller.h>
+#include "rpc/common/caller/rpc_caller_session.h"
#include <CppUTest/TestHarness.h>
TEST_GROUP(ServiceFrameworkTests)
{
- static rpc_status_t handlerThatSucceeds(void *context, struct call_req* req)
+ static rpc_status_t handlerThatSucceeds(void *context, struct rpc_request* req)
{
(void)context;
- struct call_param_buf *respBuf = call_req_get_resp_buf(req);
+ struct rpc_buffer *respBuf = &req->response;
std::string responseString("Yay!");
- respBuf->data_len = responseString.copy((char*)respBuf->data, respBuf->size);
+ respBuf->data_length = responseString.copy((char*)respBuf->data, respBuf->size);
- call_req_set_opstatus(req, SERVICE_SPECIFIC_SUCCESS_CODE);
+ req->service_status = SERVICE_SPECIFIC_SUCCESS_CODE;
- return TS_RPC_CALL_ACCEPTED;
+ return RPC_SUCCESS;
}
- static rpc_status_t handlerThatFails(void *context, struct call_req* req)
+ static rpc_status_t handlerThatFails(void *context, struct rpc_request* req)
{
(void)context;
- struct call_param_buf *respBuf = call_req_get_resp_buf(req);
+ struct rpc_buffer *respBuf = &req->response;
std::string responseString("Ehh!");
- respBuf->data_len = responseString.copy((char*)respBuf->data, respBuf->size);
+ respBuf->data_length = responseString.copy((char*)respBuf->data, respBuf->size);
- call_req_set_opstatus(req, SERVICE_SPECIFIC_ERROR_CODE);
+ req->service_status = SERVICE_SPECIFIC_ERROR_CODE;
- return TS_RPC_CALL_ACCEPTED;
+ return RPC_SUCCESS;
}
void setup()
{
- memset(&m_direct_caller, sizeof(m_direct_caller), 0);
+ memset(&m_direct_caller, 0, sizeof(m_direct_caller));
+ memset(&m_session, 0, sizeof(m_session));
}
void teardown()
{
+ rpc_caller_session_close(&m_session);
direct_caller_deinit(&m_direct_caller);
}
@@ -58,39 +61,52 @@ TEST_GROUP(ServiceFrameworkTests)
static const int SERVICE_SPECIFIC_ERROR_CODE = 101;
static const int SERVICE_SPECIFIC_SUCCESS_CODE = 100;
- struct direct_caller m_direct_caller;
+ struct rpc_caller_interface m_direct_caller;
+ struct rpc_caller_session m_session;
};
TEST(ServiceFrameworkTests, serviceWithNoOps)
{
/* Constructs a service endpoint with no handlers */
+ struct rpc_uuid service_uuid = { .uuid = {
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
struct service_provider service_provider;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
- service_provider_init(&service_provider, &service_provider, NULL, 0);
- struct rpc_caller *caller = direct_caller_init_default(&m_direct_caller,
- service_provider_get_rpc_interface(&service_provider));
+ service_provider_init(&service_provider, &service_provider, &service_uuid, NULL, 0);
+ rpc_status = direct_caller_init(&m_direct_caller,
+ service_provider_get_rpc_interface(&service_provider));
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
+
+ rpc_status = rpc_caller_session_find_and_open(&m_session, &m_direct_caller, &service_uuid,
+ 4096);
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
rpc_call_handle handle;
uint8_t *req_buf;
uint8_t *resp_buf;
size_t req_len = 100;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
- handle = rpc_caller_begin(caller, &req_buf, req_len);
+ handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
CHECK_TRUE(handle);
- rpc_status_t rpc_status = rpc_caller_invoke(caller, handle, SOME_ARBITRARY_OPCODE,
- &opstatus, &resp_buf, &resp_len);
+ rpc_status = rpc_caller_session_invoke(handle, SOME_ARBITRARY_OPCODE, &resp_buf, &resp_len,
+ &service_status);
- rpc_caller_end(caller, handle);
+ rpc_caller_session_end(handle);
- LONGS_EQUAL(TS_RPC_ERROR_INVALID_OPCODE, rpc_status);
+ LONGS_EQUAL(RPC_ERROR_INVALID_VALUE, rpc_status);
}
TEST(ServiceFrameworkTests, serviceWithOps)
{
/* Constructs a service endpoint with a couple of handlers */
+ struct rpc_uuid service_uuid = { .uuid = {
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
struct service_handler handlers[2];
handlers[0].opcode = SOME_ARBITRARY_OPCODE;
handlers[0].invoke = handlerThatSucceeds;
@@ -98,71 +114,81 @@ TEST(ServiceFrameworkTests, serviceWithOps)
handlers[1].invoke = handlerThatFails;
struct service_provider service_provider;
+ rpc_status_t rpc_status;
- service_provider_init(&service_provider, &service_provider, handlers, 2);
- struct rpc_caller *caller = direct_caller_init_default(&m_direct_caller,
- service_provider_get_rpc_interface(&service_provider));
+ service_provider_init(&service_provider, &service_provider, &service_uuid, handlers, 2);
+ rpc_status = direct_caller_init(&m_direct_caller,
+ service_provider_get_rpc_interface(&service_provider));
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
+
+ rpc_status = rpc_caller_session_find_and_open(&m_session, &m_direct_caller, &service_uuid,
+ 4096);
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
rpc_call_handle handle;
- rpc_status_t rpc_status;
uint8_t *req_buf;
uint8_t *resp_buf;
size_t req_len = 100;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
std::string respString;
/* Expect this call transaction to succeed */
- handle = rpc_caller_begin(caller, &req_buf, req_len);
+ handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
CHECK_TRUE(handle);
- rpc_status = rpc_caller_invoke(caller, handle, SOME_ARBITRARY_OPCODE,
- &opstatus, &resp_buf, &resp_len);
+ rpc_status = rpc_caller_session_invoke(handle, SOME_ARBITRARY_OPCODE, &resp_buf, &resp_len,
+ &service_status);
respString = std::string((const char*)resp_buf, resp_len);
- rpc_caller_end(caller, handle);
+ rpc_caller_session_end(handle);
- LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
- LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, service_status);
STRCMP_EQUAL("Yay!", respString.c_str());
/* Expect this call transaction to fail */
- handle = rpc_caller_begin(caller, &req_buf, req_len);
+ handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
CHECK_TRUE(handle);
- rpc_status = rpc_caller_invoke(caller, handle, ANOTHER_ARBITRARY_OPCODE,
- &opstatus, &resp_buf, &resp_len);
+ rpc_status = rpc_caller_session_invoke(handle, ANOTHER_ARBITRARY_OPCODE, &resp_buf,
+ &resp_len, &service_status);
respString = std::string((const char*)resp_buf, resp_len);
- rpc_caller_end(caller, handle);
+ rpc_caller_session_end(handle);
- LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
- LONGS_EQUAL(SERVICE_SPECIFIC_ERROR_CODE, opstatus);
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_ERROR_CODE, service_status);
STRCMP_EQUAL("Ehh!", respString.c_str());
/* Try an unsupported opcode */
- handle = rpc_caller_begin(caller, &req_buf, req_len);
+ handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
CHECK_TRUE(handle);
- rpc_status = rpc_caller_invoke(caller, handle, YET_ANOTHER_ARBITRARY_OPCODE,
- &opstatus, &resp_buf, &resp_len);
+ rpc_status = rpc_caller_session_invoke(handle, YET_ANOTHER_ARBITRARY_OPCODE, &resp_buf, &resp_len,
+ &service_status);
- rpc_caller_end(caller, handle);
+ rpc_caller_session_end(handle);
- LONGS_EQUAL(TS_RPC_ERROR_INVALID_OPCODE, rpc_status);
+ LONGS_EQUAL(RPC_ERROR_INVALID_VALUE, rpc_status);
}
TEST(ServiceFrameworkTests, serviceProviderChain)
{
+ struct rpc_uuid service_uuid = { .uuid = {
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
+ rpc_status_t rpc_status;
+
/* Construct the base service provider */
struct service_handler base_handlers[1];
base_handlers[0].opcode = 100;
base_handlers[0].invoke = handlerThatSucceeds;
struct service_provider base_provider;
- service_provider_init(&base_provider, &base_provider, base_handlers, 1);
+ service_provider_init(&base_provider, &base_provider, &service_uuid, base_handlers, 1);
/* Construct a sub provider and extend the base */
struct service_handler sub0_handlers[1];
@@ -170,7 +196,7 @@ TEST(ServiceFrameworkTests, serviceProviderChain)
sub0_handlers[0].invoke = handlerThatSucceeds;
struct service_provider sub0_provider;
- service_provider_init(&sub0_provider, &sub0_provider, sub0_handlers, 1);
+ service_provider_init(&sub0_provider, &sub0_provider, &service_uuid, sub0_handlers, 1);
service_provider_extend(&base_provider, &sub0_provider);
/* Construct another sub provider and extend the base */
@@ -179,75 +205,76 @@ TEST(ServiceFrameworkTests, serviceProviderChain)
sub1_handlers[0].invoke = handlerThatSucceeds;
struct service_provider sub1_provider;
- service_provider_init(&sub1_provider, &sub1_provider, sub1_handlers, 1);
+ service_provider_init(&sub1_provider, &sub1_provider, &service_uuid, sub1_handlers, 1);
service_provider_extend(&base_provider, &sub1_provider);
/* Use a direct_caller to make RPC calls to the base provider at the head of the chain */
- struct rpc_caller *caller = direct_caller_init_default(&m_direct_caller,
- service_provider_get_rpc_interface(&base_provider));
+ rpc_status = direct_caller_init(&m_direct_caller,
+ service_provider_get_rpc_interface(&base_provider));
+ LONGS_EQUAL(rpc_status, RPC_SUCCESS);
+
+ rpc_status = rpc_caller_session_find_and_open(&m_session, &m_direct_caller, &service_uuid,
+ 4096);
+ LONGS_EQUAL(rpc_status, RPC_SUCCESS);
rpc_call_handle handle;
- rpc_status_t rpc_status;
uint8_t *req_buf;
uint8_t *resp_buf;
size_t req_len = 100;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
std::string respString;
/* Expect calls that will be handled by all three chained service providers to succeed */
- handle = rpc_caller_begin(caller, &req_buf, req_len);
+ handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
CHECK_TRUE(handle);
- rpc_status = rpc_caller_invoke(caller, handle, 100,
- &opstatus, &resp_buf, &resp_len);
+ rpc_status = rpc_caller_session_invoke(handle, 100, &resp_buf, &resp_len, &service_status);
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
respString = std::string((const char*)resp_buf, resp_len);
- rpc_caller_end(caller, handle);
+ rpc_caller_session_end(handle);
- LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
- LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, service_status);
STRCMP_EQUAL("Yay!", respString.c_str());
/* This one should beb handled by sub0 */
- handle = rpc_caller_begin(caller, &req_buf, req_len);
+ handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
CHECK_TRUE(handle);
- rpc_status = rpc_caller_invoke(caller, handle, 200,
- &opstatus, &resp_buf, &resp_len);
+ rpc_status = rpc_caller_session_invoke(handle, 200, &resp_buf, &resp_len, &service_status);
respString = std::string((const char*)resp_buf, resp_len);
- rpc_caller_end(caller, handle);
+ rpc_caller_session_end(handle);
- LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
- LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, service_status);
STRCMP_EQUAL("Yay!", respString.c_str());
/* This one should beb handled by sub1 */
- handle = rpc_caller_begin(caller, &req_buf, req_len);
+ handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
CHECK_TRUE(handle);
- rpc_status = rpc_caller_invoke(caller, handle, 300,
- &opstatus, &resp_buf, &resp_len);
+ rpc_status = rpc_caller_session_invoke(handle, 300, &resp_buf, &resp_len, &service_status);
respString = std::string((const char*)resp_buf, resp_len);
- rpc_caller_end(caller, handle);
+ rpc_caller_session_end(handle);
- LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
- LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
+ LONGS_EQUAL(RPC_SUCCESS, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, service_status);
STRCMP_EQUAL("Yay!", respString.c_str());
/* Try an unsupported opcode */
- handle = rpc_caller_begin(caller, &req_buf, req_len);
+ handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
CHECK_TRUE(handle);
- rpc_status = rpc_caller_invoke(caller, handle, 400,
- &opstatus, &resp_buf, &resp_len);
+ rpc_status = rpc_caller_session_invoke(handle, 400, &resp_buf, &resp_len, &service_status);
- rpc_caller_end(caller, handle);
+ rpc_caller_session_end(handle);
- LONGS_EQUAL(TS_RPC_ERROR_INVALID_OPCODE, rpc_status);
+ LONGS_EQUAL(RPC_ERROR_INVALID_VALUE, rpc_status);
}
diff --git a/components/service/common/serializer/protobuf/pb_helper.h b/components/service/common/serializer/protobuf/pb_helper.h
index 1f109b0d1..61c0ae9b3 100644
--- a/components/service/common/serializer/protobuf/pb_helper.h
+++ b/components/service/common/serializer/protobuf/pb_helper.h
@@ -13,6 +13,8 @@
extern "C" {
#endif
+#define PB_PACKET_LENGTH(payload_length) ((payload_length) + 16)
+
/* Returns an initialised pb_callback_t structure for encoding a variable length byte array */
extern pb_callback_t pb_out_byte_array(const pb_bytes_array_t *byte_array);
diff --git a/components/service/crypto/backend/mbedcrypto/component.cmake b/components/service/crypto/backend/mbedcrypto/component.cmake
index 4b531b767..36fd3df22 100644
--- a/components/service/crypto/backend/mbedcrypto/component.cmake
+++ b/components/service/crypto/backend/mbedcrypto/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,19 +8,16 @@ if (NOT DEFINED TGT)
message(FATAL_ERROR "mandatory parameter TGT is not defined.")
endif()
+target_include_directories(${TGT} PRIVATE
+ "${MBEDTLS_INSTALL_DIR}/include"
+)
target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/mbedcrypto_backend.c"
)
-# Force use of the mbed crypto configuration required by the crypto service
-# provider. This configuration includes enabling the use of the PSA ITS API
-# for persistent key storage which is realised by the its client adapter
-# for the secure storage service.
-set(MBEDTLS_USER_CONFIG_FILE
- "${CMAKE_CURRENT_LIST_DIR}/config_mbedtls_user.h"
- CACHE STRING "Configuration file for Mbed TLS" FORCE)
-
+# Use secure storage client to realize PSA ITS C API used by libmbedcrypto for
+# persistent key storage.
set(MBEDTLS_EXTRA_INCLUDES
"${TS_ROOT}/components/service/common/include"
"${TS_ROOT}/components/service/secure_storage/include"
- CACHE STRING "PSA ITS for Mbed TLS" FORCE)
+ CACHE STRING "PSA ITS for MbedTLS" FORCE)
diff --git a/components/service/crypto/backend/mbedcrypto/config_mbedtls_user.h b/components/service/crypto/backend/mbedcrypto/config_mbedtls_user.h
deleted file mode 100644
index 95b6a3a73..000000000
--- a/components/service/crypto/backend/mbedcrypto/config_mbedtls_user.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef CONFIG_MBEDTLS_USER_H
-#define CONFIG_MBEDTLS_USER_H
-
-/**
- * Mbed TLS configuration for building libmbedcrypto to act as a backend
- * for the crypto service provider running in an isolated secure processing
- * environment. Note that supported crypto operations are configured
- * separately using the PSA crypto build interface (PSA_WANT_xxx). This
- * decouples Mbed TLS specific configuration from the more general crypto
- * capabilities configuration.
- */
-#define MBEDTLS_PSA_CRYPTO_CONFIG
-#define MBEDTLS_NO_UDBL_DIVISION
-#undef MBEDTLS_HAVE_TIME
-#undef MBEDTLS_HAVE_TIME_DATE
-#undef MBEDTLS_FS_IO
-#define MBEDTLS_ENTROPY_HARDWARE_ALT
-#define MBEDTLS_NO_PLATFORM_ENTROPY
-#undef MBEDTLS_SELF_TEST
-#undef MBEDTLS_PLATFORM_C
-#undef MBEDTLS_PSA_ITS_FILE_C
-#undef MBEDTLS_TIMING_C
-#undef MBEDTLS_AESNI_C
-#undef MBEDTLS_PADLOCK_C
-
-
-#endif /* CONFIG_MBEDTLS_USER_H */
diff --git a/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/component.cmake b/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/component.cmake
new file mode 100644
index 000000000..878af282f
--- /dev/null
+++ b/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/component.cmake
@@ -0,0 +1,16 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_include_directories(${TGT} PRIVATE
+ "${MBEDTLS_INSTALL_DIR}/include"
+)
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/mbedtls_fake_x509.c"
+ )
diff --git a/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/mbedtls_fake_x509.c b/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/mbedtls_fake_x509.c
new file mode 100644
index 000000000..a579252c8
--- /dev/null
+++ b/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/mbedtls_fake_x509.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mbedtls/build_info.h>
+#include <mbedtls/error.h>
+#include <mbedtls/pkcs7.h>
+#include <mbedtls/x509_crt.h>
+#include <compiler.h>
+#include <stdlib.h>
+
+#include "mbedtls_fake_x509.h"
+
+/*
+ * This file contains X509 and PKCS#7 related fake functions. When crypto SP is compiled
+ * with a minimalistic mbedtls config which does not support the aformentioned features
+ * these functions need to be included to avoid linkage errors.
+ */
+#if !defined(MBEDTLS_X509_CRT_PARSE_C)
+void mbedtls_x509_crt_init(mbedtls_x509_crt *crt)
+{
+ (void)crt;
+}
+
+int mbedtls_x509_crt_parse_der(mbedtls_x509_crt *chain,
+ const unsigned char *buf,
+ size_t buflen)
+{
+ (void)chain;
+ (void)buf;
+ (void)buflen;
+
+ return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
+}
+
+void mbedtls_x509_crt_free(mbedtls_x509_crt *crt)
+{
+ (void)crt;
+}
+#endif
+
+#if !defined(MBEDTLS_PKCS7_C)
+void mbedtls_pkcs7_init(mbedtls_pkcs7 *pkcs7)
+{
+ (void)pkcs7;
+}
+
+int mbedtls_pkcs7_parse_der(mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
+ const size_t buflen)
+{
+ (void)pkcs7;
+ (void)buf;
+ (void)buflen;
+
+ return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
+}
+
+void mbedtls_pkcs7_free(mbedtls_pkcs7 *pkcs7)
+{
+ (void)pkcs7;
+}
+
+int mbedtls_pkcs7_signed_hash_verify(mbedtls_pkcs7 *pkcs7,
+ const mbedtls_x509_crt *cert,
+ const unsigned char *hash, size_t hashlen)
+{
+ (void)pkcs7;
+ (void)cert;
+ (void)hash;
+ (void)hashlen;
+
+ return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
+}
+#endif
diff --git a/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/mbedtls_fake_x509.h b/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/mbedtls_fake_x509.h
new file mode 100644
index 000000000..f282aa7ba
--- /dev/null
+++ b/components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509/mbedtls_fake_x509.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MBEDTLS_FAKE_X509_H
+#define MBEDTLS_FAKE_X509_H
+
+
+#endif /* MBEDTLS_FAKE_X509_H */
diff --git a/components/service/crypto/backend/mbedcrypto/trng_adapter/linux/linux_trng_adapter.c b/components/service/crypto/backend/mbedcrypto/trng_adapter/linux/linux_trng_adapter.c
index 1b2f2b4bb..da8a058ca 100644
--- a/components/service/crypto/backend/mbedcrypto/trng_adapter/linux/linux_trng_adapter.c
+++ b/components/service/crypto/backend/mbedcrypto/trng_adapter/linux/linux_trng_adapter.c
@@ -1,15 +1,15 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mbedtls/entropy.h>
#include <service/crypto/backend/mbedcrypto/trng_adapter/trng_adapter.h>
+#include <psa/error.h>
#include <unistd.h>
-#include <sys/syscall.h>
+#include <linux/random.h>
+#include <sys/random.h>
#include <errno.h>
-#include <sys/syscall.h>
-#include <unistd.h>
/*
* An mbed tls compatibile hardware entropy source that adapts the mbed tls hardware poll
@@ -19,6 +19,7 @@
int trng_adapter_init(int instance)
{
(void)instance;
+ return PSA_SUCCESS;
}
void trng_adapter_deinit()
@@ -28,10 +29,18 @@ void trng_adapter_deinit()
int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen)
{
+ (void)data;
+
int status = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
*olen = 0;
- int num_output = syscall(SYS_getrandom, output, len, 0);
+ /*
+ * Use the GRND_INSECURE flag so the call won't block even if there is not
+ * enough entropy available at the time of the syscall, so the crng wasn't
+ * initialized yet. Returns possibly cryptographically insecure random data,
+ * which is fine for testing purposes.
+ */
+ int num_output = getrandom(output, len, GRND_INSECURE);
if (num_output >= 0) {
diff --git a/components/service/crypto/backend/mbedcrypto/trng_adapter/platform/component.cmake b/components/service/crypto/backend/mbedcrypto/trng_adapter/platform/component.cmake
index 575ac22ea..d2bf6d4ad 100644
--- a/components/service/crypto/backend/mbedcrypto/trng_adapter/platform/component.cmake
+++ b/components/service/crypto/backend/mbedcrypto/trng_adapter/platform/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -12,6 +12,6 @@ target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/platform_trng_adapter.c"
)
-set_property(TARGET ${TGT} APPEND_STRING PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
+set_property(TARGET ${TGT} APPEND PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
"trng"
)
diff --git a/components/service/crypto/backend/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c b/components/service/crypto/backend/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c
index f05fe6376..c509fcffb 100644
--- a/components/service/crypto/backend/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c
+++ b/components/service/crypto/backend/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c
@@ -1,12 +1,11 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mbedtls/entropy.h>
#include <platform/interface/trng.h>
#include <service/crypto/backend/mbedcrypto/trng_adapter/trng_adapter.h>
-#include <config/interface/config_store.h>
#include <psa/error.h>
#include <stddef.h>
@@ -19,17 +18,7 @@ static struct platform_trng_driver driver = {0};
int trng_adapter_init(int instance)
{
- int status = PSA_STATUS_HARDWARE_FAILURE;
- struct device_region device_region;
-
- if (config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION,
- "trng", instance,
- &device_region, sizeof(device_region))) {
-
- status = platform_trng_create(&driver, &device_region);
- }
-
- return status;
+ return platform_trng_create(&driver,instance);
}
void trng_adapter_deinit()
diff --git a/components/service/crypto/backend/psa_ipc/component.cmake b/components/service/crypto/backend/psa_ipc/component.cmake
new file mode 100644
index 000000000..1a4922fae
--- /dev/null
+++ b/components/service/crypto/backend/psa_ipc/component.cmake
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/crypto_ipc_backend.c"
+ )
+
+# The ipc crypto backend uses the psa crypto client to realize the
+# psa crypto API that the crypto provider depends on. This define
+# configures the psa crypto client to be built with the ipc crypto
+# caller.
+target_compile_definitions(${TGT} PRIVATE
+ PSA_CRYPTO_CLIENT_CALLER_SELECTION_H="service/crypto/client/caller/psa_ipc/crypto_caller.h"
+)
diff --git a/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.c b/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.c
new file mode 100644
index 000000000..9bf1c78b6
--- /dev/null
+++ b/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <psa/crypto.h>
+#include <service/crypto/client/psa/psa_crypto_client.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include "crypto_ipc_backend.h"
+
+psa_status_t crypto_ipc_backend_init(struct rpc_caller_session *session)
+{
+ psa_status_t status = psa_crypto_client_init(session);
+
+ if (status == PSA_SUCCESS)
+ status = psa_crypto_init();
+
+ return status;
+}
+
+void crypto_ipc_backend_deinit(void)
+{
+ psa_crypto_client_deinit();
+}
diff --git a/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.h b/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.h
new file mode 100644
index 000000000..27ac59837
--- /dev/null
+++ b/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_IPC_BACKEND_H
+#define CRYPTO_IPC_BACKEND_H
+
+#include <service/crypto/client/psa/psa_crypto_client.h>
+#include <psa/error.h>
+#include <rpc_caller.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief This type is used to overcome a limitation in the number of maximum
+ * IOVECs that can be used especially in psa_aead_encrypt and
+ * psa_aead_decrypt. To be removed in case the AEAD APIs number of
+ * parameters passed gets restructured
+ */
+#define TFM_CRYPTO_MAX_NONCE_LENGTH (16u)
+struct psa_ipc_crypto_aead_pack_input {
+ uint8_t nonce[TFM_CRYPTO_MAX_NONCE_LENGTH];
+ uint32_t nonce_length;
+};
+
+struct psa_ipc_crypto_pack_iovec {
+ psa_key_id_t key_id; /*!< Key id */
+ psa_algorithm_t alg; /*!< Algorithm */
+ uint32_t op_handle; /*!< Frontend context handle associated to a
+ * multipart operation
+ */
+ uint32_t capacity; /*!< Key derivation capacity */
+ uint32_t ad_length; /*!< Additional Data length for multipart AEAD */
+ uint32_t plaintext_length; /*!< Plaintext length for multipart AEAD */
+
+ struct psa_ipc_crypto_aead_pack_input aead_in; /*!< Packs AEAD-related inputs */
+
+ uint16_t function_id; /*!< Used to identify the function in the
+ * API dispatcher to the service backend
+ * See tfm_crypto_func_sid for detail
+ */
+ uint16_t step; /*!< Key derivation step */
+}__packed;
+
+#define iov_size sizeof(struct psa_ipc_crypto_pack_iovec)
+
+/**
+ * \brief Initialize the psa ipc crypto backend
+ *
+ * Initializes a crypto backend that uses the psa API client with a
+ * psa_ipc_backend caller to realize the PSA crypto API used by the crypto
+ * service proviser.
+ *
+ * \return PSA_SUCCESS if backend initialized successfully
+ */
+psa_status_t crypto_ipc_backend_init(struct rpc_caller_session *session);
+
+/**
+ * \brief Clean-up to free any resource used by the crypto backend
+ */
+void crypto_ipc_backend_deinit(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* CRYPTO_IPC_BACKEND_H */
diff --git a/components/service/crypto/backend/stub/stub_crypto_backend.c b/components/service/crypto/backend/stub/stub_crypto_backend.c
index f969b434a..edb45f8ab 100644
--- a/components/service/crypto/backend/stub/stub_crypto_backend.c
+++ b/components/service/crypto/backend/stub/stub_crypto_backend.c
@@ -13,11 +13,20 @@
psa_status_t stub_crypto_backend_init(void)
{
- static struct dummy_caller dummy_caller;
- struct rpc_caller *caller = dummy_caller_init(&dummy_caller,
- TS_RPC_CALL_ACCEPTED, PSA_ERROR_SERVICE_FAILURE);
+ static struct rpc_caller_interface dummy_caller;
+ struct rpc_caller_session session = { 0 };
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
- psa_status_t status = psa_crypto_client_init(caller);
+ rpc_status = dummy_caller_init(&dummy_caller, RPC_SUCCESS, PSA_ERROR_SERVICE_FAILURE);
+ if (rpc_status != RPC_SUCCESS)
+ return PSA_ERROR_GENERIC_ERROR;
+
+ rpc_status = rpc_caller_session_find_and_open(&session, &dummy_caller, NULL, 0);
+ if (rpc_status != RPC_SUCCESS)
+ return PSA_ERROR_GENERIC_ERROR;
+
+ status = psa_crypto_client_init(&session);
if (status == PSA_SUCCESS)
status = psa_crypto_init();
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller.h b/components/service/crypto/client/caller/packed-c/crypto_caller.h
index e41a8cbdd..d834bc207 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,22 +13,23 @@
* provided by a crypto service instance using the packed-c serialization.
*/
#include "crypto_caller_aead.h"
-#include "crypto_caller_copy_key.h"
-#include "crypto_caller_generate_key.h"
-#include "crypto_caller_hash.h"
-#include "crypto_caller_mac.h"
#include "crypto_caller_asymmetric_decrypt.h"
+#include "crypto_caller_asymmetric_encrypt.h"
+#include "crypto_caller_cipher.h"
+#include "crypto_caller_copy_key.h"
#include "crypto_caller_destroy_key.h"
+#include "crypto_caller_export_key.h"
+#include "crypto_caller_export_public_key.h"
+#include "crypto_caller_generate_key.h"
#include "crypto_caller_generate_random.h"
+#include "crypto_caller_get_key_attributes.h"
+#include "crypto_caller_hash.h"
#include "crypto_caller_import_key.h"
+#include "crypto_caller_key_derivation.h"
+#include "crypto_caller_mac.h"
#include "crypto_caller_purge_key.h"
-#include "crypto_caller_asymmetric_encrypt.h"
-#include "crypto_caller_export_key.h"
-#include "crypto_caller_get_key_attributes.h"
#include "crypto_caller_sign_hash.h"
-#include "crypto_caller_cipher.h"
-#include "crypto_caller_export_public_key.h"
-#include "crypto_caller_key_derivation.h"
#include "crypto_caller_verify_hash.h"
+#include "crypto_caller_verify_pkcs7_signature.h"
#endif /* PACKEDC_CRYPTO_CALLER_H */
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_aead.h b/components/service/crypto/client/caller/packed-c/crypto_caller_aead.h
index 3d9947d51..bf39762b0 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_aead.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_aead.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,6 +10,7 @@
#include <string.h>
#include <stdlib.h>
#include <psa/crypto.h>
+#include "rpc_caller_session.h"
#include <service/common/client/service_client.h>
#include <protocols/rpc/common/packed-c/status.h>
#include <protocols/service/crypto/packed-c/opcodes.h>
@@ -20,38 +21,6 @@
extern "C" {
#endif
-static inline psa_status_t crypto_caller_aead_encrypt(struct service_client *context,
- psa_key_id_t key,
- psa_algorithm_t alg,
- const uint8_t *nonce,
- size_t nonce_length,
- const uint8_t *additional_data,
- size_t additional_data_length,
- const uint8_t *plaintext,
- size_t plaintext_length,
- uint8_t *aeadtext,
- size_t aeadtext_size,
- size_t *aeadtext_length)
-{
- return PSA_ERROR_NOT_SUPPORTED;
-}
-
-static inline psa_status_t crypto_caller_aead_decrypt(struct service_client *context,
- psa_key_id_t key,
- psa_algorithm_t alg,
- const uint8_t *nonce,
- size_t nonce_length,
- const uint8_t *additional_data,
- size_t additional_data_length,
- const uint8_t *aeadtext,
- size_t aeadtext_length,
- uint8_t *plaintext,
- size_t plaintext_size,
- size_t *plaintext_length)
-{
- return PSA_ERROR_NOT_SUPPORTED;
-}
-
static inline psa_status_t common_aead_setup(struct service_client *context,
uint32_t *op_handle,
psa_key_id_t key,
@@ -68,23 +37,24 @@ static inline psa_status_t common_aead_setup(struct service_client *context,
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ sizeof(struct ts_crypto_aead_setup_out));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- opcode, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, opcode,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -101,7 +71,7 @@ static inline psa_status_t common_aead_setup(struct service_client *context,
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -142,23 +112,23 @@ static inline psa_status_t crypto_caller_aead_generate_nonce(struct service_clie
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_AEAD_GENERATE_NONCE, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_GENERATE_NONCE,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -186,7 +156,7 @@ static inline psa_status_t crypto_caller_aead_generate_nonce(struct service_clie
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -214,13 +184,13 @@ static inline psa_status_t crypto_caller_aead_set_nonce(struct service_client *c
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -229,12 +199,13 @@ static inline psa_status_t crypto_caller_aead_set_nonce(struct service_client *c
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_AEAD_SET_NONCE, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_SET_NONCE,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -247,7 +218,7 @@ static inline psa_status_t crypto_caller_aead_set_lengths(struct service_client
{
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_aead_set_lengths_in req_msg;
- size_t req_fixed_len = sizeof(struct ts_crypto_aead_abort_in);
+ size_t req_fixed_len = sizeof(struct ts_crypto_aead_set_lengths_in);
size_t req_len = req_fixed_len;
req_msg.op_handle = op_handle;
@@ -257,23 +228,24 @@ static inline psa_status_t crypto_caller_aead_set_lengths(struct service_client
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_AEAD_SET_LENGTHS, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_SET_LENGTHS,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -301,13 +273,13 @@ static inline psa_status_t crypto_caller_aead_update_ad(struct service_client *c
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -316,12 +288,13 @@ static inline psa_status_t crypto_caller_aead_update_ad(struct service_client *c
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_AEAD_UPDATE_AD, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_UPDATE_AD,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -353,13 +326,13 @@ static inline psa_status_t crypto_caller_aead_update(struct service_client *cont
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -368,12 +341,12 @@ static inline psa_status_t crypto_caller_aead_update(struct service_client *cont
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_AEAD_UPDATE, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_UPDATE,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -401,7 +374,7 @@ static inline psa_status_t crypto_caller_aead_update(struct service_client *cont
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -428,23 +401,23 @@ static inline psa_status_t crypto_caller_aead_finish(struct service_client *cont
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_AEAD_FINISH, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_FINISH,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -490,7 +463,7 @@ static inline psa_status_t crypto_caller_aead_finish(struct service_client *cont
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -522,13 +495,13 @@ static inline psa_status_t crypto_caller_aead_verify(struct service_client *cont
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -537,12 +510,12 @@ static inline psa_status_t crypto_caller_aead_verify(struct service_client *cont
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_AEAD_VERIFY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_VERIFY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -570,7 +543,7 @@ static inline psa_status_t crypto_caller_aead_verify(struct service_client *cont
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -589,28 +562,63 @@ static inline psa_status_t crypto_caller_aead_abort(struct service_client *conte
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_AEAD_ABORT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_AEAD_ABORT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
}
+/**
+ * The maximum data length that may be carried in an update operation will be
+ * constrained by the maximum call payload capacity imposed by the end-to-end
+ * RPC call path. These functions return the maximum update size when serialization
+ * overheads are considered. This allows large paylaods to be processed in
+ * maximum size chunks.
+ */
+static inline size_t crypto_caller_aead_max_update_ad_size(const struct service_client *context)
+{
+ /* Returns the maximum number of bytes of additional data that may be
+ * carried as a parameter of the aead_update_ad operation
+ * using the packed-c encoding.
+ */
+ size_t payload_space = context->service_info.max_payload;
+ size_t overhead = sizeof(struct ts_crypto_aead_update_ad_in) + TLV_HDR_LEN;
+
+ return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+static inline size_t crypto_caller_aead_max_update_size(const struct service_client *context)
+{
+ /* Returns the maximum number of bytes that may be
+ * carried as a parameter of the aead_update operation
+ * using the packed-c encoding.
+ */
+ size_t payload_space = context->service_info.max_payload;
+ size_t overhead = sizeof(struct ts_crypto_aead_update_in) + TLV_HDR_LEN;
+
+ /* Allow for output to be a whole number of blocks */
+ overhead += PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE;
+
+ return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_decrypt.h b/components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_decrypt.h
index 3ff6b52d5..9b3a68c10 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_decrypt.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_decrypt.h
@@ -54,13 +54,13 @@ static inline psa_status_t crypto_caller_asymmetric_decrypt(struct service_clien
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -70,12 +70,12 @@ static inline psa_status_t crypto_caller_asymmetric_decrypt(struct service_clien
if (salt) tlv_encode(&req_iter, &salt_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -103,7 +103,7 @@ static inline psa_status_t crypto_caller_asymmetric_decrypt(struct service_clien
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_encrypt.h b/components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_encrypt.h
index 8ad40a35f..a2605260b 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_encrypt.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_asymmetric_encrypt.h
@@ -54,13 +54,14 @@ static inline psa_status_t crypto_caller_asymmetric_encrypt(struct service_clien
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(output_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
+ service_status_t service_status = PSA_ERROR_GENERIC_ERROR;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -70,12 +71,12 @@ static inline psa_status_t crypto_caller_asymmetric_encrypt(struct service_clien
if (salt) tlv_encode(&req_iter, &salt_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -103,7 +104,7 @@ static inline psa_status_t crypto_caller_asymmetric_encrypt(struct service_clien
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_cipher.h b/components/service/crypto/client/caller/packed-c/crypto_caller_cipher.h
index 632ca35cb..de087dac1 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_cipher.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_cipher.h
@@ -36,23 +36,23 @@ static inline psa_status_t common_cipher_setup(struct service_client *context,
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- opcode, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, opcode, &resp_buf, &resp_len,
+ &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -69,7 +69,7 @@ static inline psa_status_t common_cipher_setup(struct service_client *context,
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -110,23 +110,25 @@ static inline psa_status_t crypto_caller_cipher_generate_iv(struct service_clien
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(iv_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_CIPHER_GENERATE_IV, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_CIPHER_GENERATE_IV, &resp_buf, &resp_len,
+ &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -154,7 +156,7 @@ static inline psa_status_t crypto_caller_cipher_generate_iv(struct service_clien
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -182,13 +184,13 @@ static inline psa_status_t crypto_caller_cipher_set_iv(struct service_client *co
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -197,12 +199,13 @@ static inline psa_status_t crypto_caller_cipher_set_iv(struct service_client *co
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_CIPHER_SET_IV, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_CIPHER_SET_IV,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -234,13 +237,13 @@ static inline psa_status_t crypto_caller_cipher_update(struct service_client *co
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -249,12 +252,12 @@ static inline psa_status_t crypto_caller_cipher_update(struct service_client *co
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_CIPHER_UPDATE, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_CIPHER_UPDATE,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -282,7 +285,7 @@ static inline psa_status_t crypto_caller_cipher_update(struct service_client *co
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -305,23 +308,23 @@ static inline psa_status_t crypto_caller_cipher_finish(struct service_client *co
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_CIPHER_FINISH, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_CIPHER_FINISH,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -349,7 +352,7 @@ static inline psa_status_t crypto_caller_cipher_finish(struct service_client *co
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -368,23 +371,24 @@ static inline psa_status_t crypto_caller_cipher_abort(struct service_client *con
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_CIPHER_ABORT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_CIPHER_ABORT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_copy_key.h b/components/service/crypto/client/caller/packed-c/crypto_caller_copy_key.h
index 8336bdffa..0e03ebe62 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_copy_key.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_copy_key.h
@@ -37,22 +37,24 @@ static inline psa_status_t crypto_caller_copy_key(struct service_client *context
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ sizeof(struct ts_crypto_copy_key_out));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
- context->rpc_status = rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_COPY_KEY, &opstatus, &resp_buf, &resp_len);
+ context->rpc_status =
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_COPY_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -69,7 +71,7 @@ static inline psa_status_t crypto_caller_copy_key(struct service_client *context
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_destroy_key.h b/components/service/crypto/client/caller/packed-c/crypto_caller_destroy_key.h
index ed3c81c97..0a88ab50f 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_destroy_key.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_destroy_key.h
@@ -19,37 +19,38 @@ extern "C" {
#endif
static inline psa_status_t crypto_caller_destroy_key(struct service_client *context,
- psa_key_id_t id)
+ psa_key_id_t id)
{
- psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
- struct ts_crypto_destroy_key_in req_msg;
- size_t req_len = sizeof(struct ts_crypto_destroy_key_in);
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ struct ts_crypto_destroy_key_in req_msg;
+ size_t req_len = sizeof(struct ts_crypto_destroy_key_in);
- req_msg.id = id;
+ req_msg.id = id;
- rpc_call_handle call_handle;
- uint8_t *req_buf;
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
- if (call_handle) {
+ if (call_handle) {
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
- memcpy(req_buf, &req_msg, req_len);
+ memcpy(req_buf, &req_msg, req_len);
- context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_DESTROY_KEY, &opstatus, &resp_buf, &resp_len);
+ context->rpc_status =
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_DESTROY_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
- }
+ rpc_caller_session_end(call_handle);
+ }
- return psa_status;
+ return psa_status;
}
#ifdef __cplusplus
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_export_key.h b/components/service/crypto/client/caller/packed-c/crypto_caller_export_key.h
index fb25ad226..bad11f6e2 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_export_key.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_export_key.h
@@ -36,23 +36,24 @@ static inline psa_status_t crypto_caller_export_key(struct service_client *conte
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(data_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_EXPORT_KEY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_EXPORT_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -80,7 +81,7 @@ static inline psa_status_t crypto_caller_export_key(struct service_client *conte
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_export_public_key.h b/components/service/crypto/client/caller/packed-c/crypto_caller_export_public_key.h
index 465e86a6a..0710af663 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_export_public_key.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_export_public_key.h
@@ -35,23 +35,24 @@ static inline psa_status_t crypto_caller_export_public_key(struct service_client
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(data_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -79,7 +80,7 @@ static inline psa_status_t crypto_caller_export_public_key(struct service_client
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_generate_key.h b/components/service/crypto/client/caller/packed-c/crypto_caller_generate_key.h
index ccc952f9d..2dd67d5ed 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_generate_key.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_generate_key.h
@@ -37,23 +37,24 @@ static inline psa_status_t crypto_caller_generate_key(struct service_client *con
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ sizeof(struct ts_crypto_generate_key_out));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_GENERATE_KEY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_GENERATE_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -70,7 +71,7 @@ static inline psa_status_t crypto_caller_generate_key(struct service_client *con
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_generate_random.h b/components/service/crypto/client/caller/packed-c/crypto_caller_generate_random.h
index 33a0779c7..b9711bb9f 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_generate_random.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_generate_random.h
@@ -31,23 +31,24 @@ static inline psa_status_t crypto_caller_generate_random(struct service_client *
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(output_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_GENERATE_RANDOM, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_GENERATE_RANDOM,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -74,7 +75,7 @@ static inline psa_status_t crypto_caller_generate_random(struct service_client *
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_get_key_attributes.h b/components/service/crypto/client/caller/packed-c/crypto_caller_get_key_attributes.h
index 9ea3eb4d7..1a79bc3ae 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_get_key_attributes.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_get_key_attributes.h
@@ -32,23 +32,24 @@ static inline psa_status_t crypto_caller_get_key_attributes(struct service_clien
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ sizeof(struct ts_crypto_get_key_attributes_out));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_GET_KEY_ATTRIBUTES, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_GET_KEY_ATTRIBUTES,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -66,7 +67,7 @@ static inline psa_status_t crypto_caller_get_key_attributes(struct service_clien
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_hash.h b/components/service/crypto/client/caller/packed-c/crypto_caller_hash.h
index 3dfa6de24..924f15e55 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_hash.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_hash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -33,23 +33,23 @@ static inline psa_status_t crypto_caller_hash_setup(struct service_client *conte
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_HASH_SETUP, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_HASH_SETUP,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -66,7 +66,7 @@ static inline psa_status_t crypto_caller_hash_setup(struct service_client *conte
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -94,13 +94,13 @@ static inline psa_status_t crypto_caller_hash_update(struct service_client *cont
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -109,12 +109,13 @@ static inline psa_status_t crypto_caller_hash_update(struct service_client *cont
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_HASH_UPDATE, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_HASH_UPDATE,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -137,23 +138,24 @@ static inline psa_status_t crypto_caller_hash_finish(struct service_client *cont
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(hash_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_HASH_FINISH, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_HASH_FINISH,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -181,7 +183,7 @@ static inline psa_status_t crypto_caller_hash_finish(struct service_client *cont
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -200,23 +202,24 @@ static inline psa_status_t crypto_caller_hash_abort(struct service_client *conte
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_HASH_ABORT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_HASH_ABORT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -244,13 +247,13 @@ static inline psa_status_t crypto_caller_hash_verify(struct service_client *cont
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -259,12 +262,13 @@ static inline psa_status_t crypto_caller_hash_verify(struct service_client *cont
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_HASH_VERIFY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_HASH_VERIFY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -284,23 +288,23 @@ static inline psa_status_t crypto_caller_hash_clone(struct service_client *conte
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_HASH_CLONE, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_HASH_CLONE,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -317,29 +321,12 @@ static inline psa_status_t crypto_caller_hash_clone(struct service_client *conte
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
}
-static inline psa_status_t crypto_caller_hash_suspend(struct service_client *context,
- uint32_t op_handle,
- uint8_t *hash_state,
- size_t hash_state_size,
- size_t *hash_state_length)
-{
- return PSA_ERROR_NOT_SUPPORTED;
-}
-
-static inline psa_status_t crypto_caller_hash_resume(struct service_client *context,
- uint32_t op_handle,
- const uint8_t *hash_state,
- size_t hash_state_length)
-{
- return PSA_ERROR_NOT_SUPPORTED;
-}
-
static inline size_t crypto_caller_hash_max_update_size(const struct service_client *context)
{
/* Returns the maximum number of bytes that may be
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_import_key.h b/components/service/crypto/client/caller/packed-c/crypto_caller_import_key.h
index 8c1949dd7..bc2e6d7c5 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_import_key.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_import_key.h
@@ -45,13 +45,13 @@ static inline psa_status_t crypto_caller_import_key(struct service_client *conte
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -60,12 +60,12 @@ static inline psa_status_t crypto_caller_import_key(struct service_client *conte
tlv_encode(&req_iter, &key_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_IMPORT_KEY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_IMPORT_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -82,7 +82,7 @@ static inline psa_status_t crypto_caller_import_key(struct service_client *conte
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_key_derivation.h b/components/service/crypto/client/caller/packed-c/crypto_caller_key_derivation.h
index 496f07e15..c60e02d56 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_key_derivation.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_key_derivation.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -34,23 +34,24 @@ static inline psa_status_t crypto_caller_key_derivation_setup(struct service_cli
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_SETUP, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_SETUP,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -67,7 +68,7 @@ static inline psa_status_t crypto_caller_key_derivation_setup(struct service_cli
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -86,23 +87,24 @@ static inline psa_status_t crypto_caller_key_derivation_get_capacity(struct serv
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_GET_CAPACITY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_GET_CAPACITY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -119,7 +121,7 @@ static inline psa_status_t crypto_caller_key_derivation_get_capacity(struct serv
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -139,23 +141,25 @@ static inline psa_status_t crypto_caller_key_derivation_set_capacity(struct serv
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_SET_CAPACITY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_SET_CAPACITY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -185,13 +189,13 @@ static inline psa_status_t crypto_caller_key_derivation_input_bytes(struct servi
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -200,12 +204,14 @@ static inline psa_status_t crypto_caller_key_derivation_input_bytes(struct servi
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_BYTES, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_BYTES,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -227,23 +233,25 @@ static inline psa_status_t crypto_caller_key_derivation_input_key(struct service
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_KEY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_INPUT_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -265,23 +273,25 @@ static inline psa_status_t crypto_caller_key_derivation_output_bytes(struct serv
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(output_length));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_BYTES, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_BYTES,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -308,7 +318,7 @@ static inline psa_status_t crypto_caller_key_derivation_output_bytes(struct serv
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -322,6 +332,7 @@ static inline psa_status_t crypto_caller_key_derivation_output_key(struct servic
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
struct ts_crypto_key_derivation_output_key_in req_msg;
size_t req_len = sizeof(struct ts_crypto_key_derivation_output_key_in);
+ size_t resp_len = sizeof(struct ts_crypto_key_derivation_output_key_out);
/* Set default outputs for failure case */
*key = 0;
@@ -332,23 +343,24 @@ static inline psa_status_t crypto_caller_key_derivation_output_key(struct servic
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, resp_len);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_KEY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_OUTPUT_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -366,7 +378,7 @@ static inline psa_status_t crypto_caller_key_derivation_output_key(struct servic
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -385,23 +397,25 @@ static inline psa_status_t crypto_caller_key_derivation_abort(struct service_cli
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_ABORT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_ABORT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -433,13 +447,13 @@ static inline psa_status_t crypto_caller_key_derivation_key_agreement(struct ser
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -448,12 +462,14 @@ static inline psa_status_t crypto_caller_key_derivation_key_agreement(struct ser
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_KEY_AGREEMENT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_KEY_AGREEMENT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -486,13 +502,13 @@ static inline psa_status_t crypto_caller_raw_key_agreement(struct service_client
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -501,12 +517,13 @@ static inline psa_status_t crypto_caller_raw_key_agreement(struct service_client
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_KEY_DERIVATION_RAW_KEY_AGREEMENT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle,
+ TS_CRYPTO_OPCODE_KEY_DERIVATION_RAW_KEY_AGREEMENT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -524,7 +541,7 @@ static inline psa_status_t crypto_caller_raw_key_agreement(struct service_client
}
else {
/* Insufficient buffer space */
- psa_status = PSA_ERROR_INVALID_ARGUMENT;
+ psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
}
}
else {
@@ -534,7 +551,7 @@ static inline psa_status_t crypto_caller_raw_key_agreement(struct service_client
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_mac.h b/components/service/crypto/client/caller/packed-c/crypto_caller_mac.h
index 739f31202..c476da0fb 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_mac.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_mac.h
@@ -36,23 +36,23 @@ static inline psa_status_t common_mac_setup(struct service_client *context,
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- opcode, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, opcode, &resp_buf, &resp_len,
+ &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -69,7 +69,7 @@ static inline psa_status_t common_mac_setup(struct service_client *context,
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -113,13 +113,13 @@ static inline psa_status_t crypto_caller_mac_update(struct service_client *conte
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -128,12 +128,13 @@ static inline psa_status_t crypto_caller_mac_update(struct service_client *conte
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_MAC_UPDATE, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_MAC_UPDATE,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -156,23 +157,24 @@ static inline psa_status_t crypto_caller_mac_sign_finish(struct service_client *
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(mac_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_MAC_SIGN_FINISH, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_MAC_SIGN_FINISH,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -200,7 +202,7 @@ static inline psa_status_t crypto_caller_mac_sign_finish(struct service_client *
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -228,13 +230,13 @@ static inline psa_status_t crypto_caller_mac_verify_finish(struct service_client
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -243,12 +245,13 @@ static inline psa_status_t crypto_caller_mac_verify_finish(struct service_client
tlv_encode(&req_iter, &data_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_MAC_VERIFY_FINISH, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_MAC_VERIFY_FINISH,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
@@ -267,23 +270,24 @@ static inline psa_status_t crypto_caller_mac_abort(struct service_client *contex
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_fixed_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_MAC_ABORT, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_MAC_ABORT,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_purge_key.h b/components/service/crypto/client/caller/packed-c/crypto_caller_purge_key.h
index 84af48f77..be3043407 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_purge_key.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_purge_key.h
@@ -30,23 +30,24 @@ static inline psa_status_t crypto_caller_purge_key(struct service_client *contex
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, &req_msg, req_len);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_PURGE_KEY, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, TS_CRYPTO_OPCODE_PURGE_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_sign_hash.h b/components/service/crypto/client/caller/packed-c/crypto_caller_sign_hash.h
index e807773eb..1de03b280 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_sign_hash.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_sign_hash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,7 +20,8 @@
extern "C" {
#endif
-static inline psa_status_t crypto_caller_sign_hash(struct service_client *context,
+static inline psa_status_t crypto_caller_asym_sign_commom(struct service_client *context,
+ uint32_t opcode,
psa_key_id_t id,
psa_algorithm_t alg,
const uint8_t *hash, size_t hash_length,
@@ -44,13 +45,14 @@ static inline psa_status_t crypto_caller_sign_hash(struct service_client *contex
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len,
+ tlv_required_space(signature_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -59,12 +61,12 @@ static inline psa_status_t crypto_caller_sign_hash(struct service_client *contex
tlv_encode(&req_iter, &hash_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_SIGN_HASH, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, opcode, &resp_buf, &resp_len,
+ &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (context->rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -92,12 +94,34 @@ static inline psa_status_t crypto_caller_sign_hash(struct service_client *contex
}
}
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
}
+static inline psa_status_t crypto_caller_sign_hash(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
+ return crypto_caller_asym_sign_commom(context, TS_CRYPTO_OPCODE_SIGN_HASH,
+ id, alg, hash, hash_length,
+ signature, signature_size, signature_length);
+}
+
+static inline psa_status_t crypto_caller_sign_message(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
+ return crypto_caller_asym_sign_commom(context, TS_CRYPTO_OPCODE_SIGN_MESSAGE,
+ id, alg, hash, hash_length,
+ signature, signature_size, signature_length);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_verify_hash.h b/components/service/crypto/client/caller/packed-c/crypto_caller_verify_hash.h
index 47152946e..1f3d46ea2 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_verify_hash.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_verify_hash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,7 +20,8 @@
extern "C" {
#endif
-static inline psa_status_t crypto_caller_verify_hash(struct service_client *context,
+static inline psa_status_t crypto_caller_asym_verify_common(struct service_client *context,
+ uint32_t opcode,
psa_key_id_t id,
psa_algorithm_t alg,
const uint8_t *hash, size_t hash_length,
@@ -48,13 +49,13 @@ static inline psa_status_t crypto_caller_verify_hash(struct service_client *cont
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(context->caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
struct tlv_iterator req_iter;
memcpy(req_buf, &req_msg, req_fixed_len);
@@ -64,17 +65,44 @@ static inline psa_status_t crypto_caller_verify_hash(struct service_client *cont
tlv_encode(&req_iter, &sig_record);
context->rpc_status =
- rpc_caller_invoke(context->caller, call_handle,
- TS_CRYPTO_OPCODE_VERIFY_HASH, &opstatus, &resp_buf, &resp_len);
+ rpc_caller_session_invoke(call_handle, opcode, &resp_buf, &resp_len,
+ &service_status);
- if (context->rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (context->rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(context->caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return psa_status;
}
+static inline psa_status_t crypto_caller_verify_hash(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length)
+{
+ return crypto_caller_asym_verify_common(context,
+ TS_CRYPTO_OPCODE_VERIFY_HASH,
+ id, alg,
+ hash, hash_length,
+ signature, signature_length);
+}
+
+static inline psa_status_t crypto_caller_verify_message(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *input, size_t input_length,
+ const uint8_t *signature, size_t signature_length)
+{
+ return crypto_caller_asym_verify_common(context,
+ TS_CRYPTO_OPCODE_VERIFY_MESSAGE,
+ id, alg,
+ input, input_length,
+ signature, signature_length);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_verify_pkcs7_signature.h b/components/service/crypto/client/caller/packed-c/crypto_caller_verify_pkcs7_signature.h
new file mode 100644
index 000000000..53335d572
--- /dev/null
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_verify_pkcs7_signature.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_CRYPTO_CALLER_VERIFY_PKCS7_SIGNATURE_H
+#define PACKEDC_CRYPTO_CALLER_VERIFY_PKCS7_SIGNATURE_H
+
+#include <common/tlv/tlv.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/verify_pkcs7_signature.h>
+#include <service/common/client/service_client.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline int crypto_caller_verify_pkcs7_signature(struct service_client *context,
+ const uint8_t *signature_cert,
+ uint64_t signature_cert_len,
+ const uint8_t *hash, uint64_t hash_len,
+ const uint8_t *public_key_cert,
+ uint64_t public_key_cert_len)
+{
+ int status = RPC_ERROR_INTERNAL;
+ size_t req_len = 0;
+
+ if (signature_cert_len > UINT16_MAX ||
+ hash_len > UINT16_MAX ||
+ public_key_cert_len > signature_cert_len)
+ return RPC_ERROR_INVALID_VALUE;
+
+ struct tlv_record signature_record = {
+ .tag = TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_SIGNATURE,
+ .length = (uint16_t)signature_cert_len,
+ .value = signature_cert
+ };
+
+ struct tlv_record hash_record = { .tag = TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_HASH,
+ .length = (uint16_t)hash_len,
+ .value = hash };
+
+ struct tlv_record public_key_record = {
+ .tag = TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_PUBLIC_KEY_CERT,
+ .length = (uint16_t)public_key_cert_len,
+ .value = public_key_cert
+ };
+
+ req_len += tlv_required_space(signature_record.length);
+ req_len += tlv_required_space(hash_record.length);
+ req_len += tlv_required_space(public_key_record.length);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+ struct tlv_iterator req_iter;
+
+ tlv_iterator_begin(&req_iter, req_buf, req_len);
+ tlv_encode(&req_iter, &signature_record);
+ tlv_encode(&req_iter, &hash_record);
+ tlv_encode(&req_iter, &public_key_record);
+
+ context->rpc_status = rpc_caller_session_invoke(
+ call_handle, TS_CRYPTO_OPCODE_VERIFY_PKCS7_SIGNATURE, &resp_buf, &resp_len,
+ &service_status);
+
+ if (context->rpc_status == RPC_SUCCESS)
+ status = service_status;
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PACKEDC_CRYPTO_CALLER_VERIFY_PKCS7_SIGNATURE_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller.h
new file mode 100644
index 000000000..99a5ed39d
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_H
+#define PSA_IPC_CRYPTO_CALLER_H
+
+/**
+ * Includes all header files that form the psa ipc crypto caller
+ * interface. May be used by a client that needs to call operations
+ * provided by a crypto service instance using the psa ipc interface.
+ */
+#include "crypto_caller_aead.h"
+#include "crypto_caller_asymmetric_decrypt.h"
+#include "crypto_caller_asymmetric_encrypt.h"
+#include "crypto_caller_cipher.h"
+#include "crypto_caller_copy_key.h"
+#include "crypto_caller_destroy_key.h"
+#include "crypto_caller_export_key.h"
+#include "crypto_caller_export_public_key.h"
+#include "crypto_caller_generate_key.h"
+#include "crypto_caller_generate_random.h"
+#include "crypto_caller_get_key_attributes.h"
+#include "crypto_caller_hash.h"
+#include "crypto_caller_import_key.h"
+#include "crypto_caller_key_derivation.h"
+#include "crypto_caller_mac.h"
+#include "crypto_caller_purge_key.h"
+#include "crypto_caller_sign_hash.h"
+#include "crypto_caller_verify_hash.h"
+
+#endif /* PSA_IPC_CRYPTO_CALLER_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_aead.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_aead.h
new file mode 100644
index 000000000..64e9c61c6
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_aead.h
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_AEAD_H
+#define PSA_IPC_CRYPTO_CALLER_AEAD_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_aead_encrypt(
+ struct service_client *context,
+ psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *plaintext,
+ size_t plaintext_length,
+ uint8_t *aeadtext,
+ size_t aeadtext_size,
+ size_t *aeadtext_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ size_t in_len;
+ int i;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_ENCRYPT_SID,
+ .key_id = key,
+ .alg = alg,
+ .aead_in = { .nonce = {0}, .nonce_length = nonce_length },
+ };
+
+ if (!additional_data && additional_data_length)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(plaintext),
+ .len = plaintext_length },
+ { .base = psa_ptr_const_to_u32(additional_data),
+ .len = additional_data_length},
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(aeadtext), .len = aeadtext_size },
+ };
+
+ if (nonce_length > TFM_CRYPTO_MAX_NONCE_LENGTH)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (nonce) {
+ for (i = 0; i < nonce_length; i++)
+ iov.aead_in.nonce[i] = nonce[i];
+ }
+
+ in_len = IOVEC_LEN(in_vec);
+
+ if (!additional_data)
+ in_len--;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ in_len, out_vec, IOVEC_LEN(out_vec));
+
+ *aeadtext_length = out_vec[0].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_decrypt(
+ struct service_client *context,
+ psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *aeadtext,
+ size_t aeadtext_length,
+ uint8_t *plaintext,
+ size_t plaintext_size,
+ size_t *plaintext_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ size_t in_len;
+ int i;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_DECRYPT_SID,
+ .key_id = key,
+ .alg = alg,
+ .aead_in = { .nonce = {0}, .nonce_length = nonce_length },
+ };
+
+ if (!additional_data && additional_data_length)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(aeadtext),
+ .len = aeadtext_length },
+ { .base = psa_ptr_const_to_u32(additional_data),
+ .len = additional_data_length},
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(plaintext), .len = plaintext_size },
+ };
+
+ if (nonce_length > TFM_CRYPTO_MAX_NONCE_LENGTH)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (nonce) {
+ for (i = 0; i < nonce_length; i++)
+ iov.aead_in.nonce[i] = nonce[i];
+ }
+
+ in_len = IOVEC_LEN(in_vec);
+
+ if (!additional_data)
+ in_len--;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ in_len, out_vec, IOVEC_LEN(out_vec));
+
+ *plaintext_length = out_vec[0].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_encrypt_setup(
+ struct service_client *context,
+ uint32_t *op_handle,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_ENCRYPT_SETUP_SID,
+ .key_id = key,
+ .alg = alg,
+ .op_handle = (*op_handle),
+ };
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_decrypt_setup(
+ struct service_client *context,
+ uint32_t *op_handle,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_DECRYPT_SETUP_SID,
+ .key_id = key,
+ .alg = alg,
+ .op_handle = (*op_handle),
+ };
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) }
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_generate_nonce(
+ struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *nonce,
+ size_t nonce_size,
+ size_t *nonce_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_GENERATE_NONCE_SID,
+ .op_handle = op_handle,
+ };
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(nonce), .len = nonce_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *nonce_length = out_vec[0].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_set_nonce(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *nonce,
+ size_t nonce_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_SET_NONCE_SID,
+ .op_handle = op_handle,
+ };
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ { .base = psa_ptr_const_to_u32(nonce), .len = nonce_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_set_lengths(
+ struct service_client *context,
+ uint32_t op_handle,
+ size_t ad_length,
+ size_t plaintext_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_SET_LENGTHS_SID,
+ .ad_length = ad_length,
+ .plaintext_length = plaintext_length,
+ .op_handle = op_handle,
+ };
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_update_ad(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *input,
+ size_t input_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_UPDATE_AD_SID,
+ .op_handle = op_handle,
+ };
+
+ /* Sanitize the optional input */
+ if ((input == NULL) && (input_length != 0)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ { .base = psa_ptr_const_to_u32(input), .len = input_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ size_t in_len = IOVEC_LEN(in_vec);
+
+ if (input == NULL)
+ in_len--;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ in_len, out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_update(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_UPDATE_SID,
+ .op_handle = op_handle,
+ };
+
+ /* Sanitize the optional input */
+ if ((input == NULL) && (input_length != 0)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ { .base = psa_ptr_const_to_u32(input), .len = input_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_const_to_u32(output), .len = output_size },
+ };
+
+ size_t in_len = IOVEC_LEN(in_vec);
+
+ if (input == NULL)
+ in_len--;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ in_len, out_vec, IOVEC_LEN(out_vec));
+
+ *output_length = out_vec[0].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_finish(
+ struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *aeadtext,
+ size_t aeadtext_size,
+ size_t *aeadtext_length,
+ uint8_t *tag,
+ size_t tag_size,
+ size_t *tag_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_FINISH_SID,
+ .op_handle = op_handle,
+ };
+
+ /* Sanitize the optional output */
+ if ((aeadtext == NULL) && (aeadtext_size != 0)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ { .base = psa_ptr_const_to_u32(tag), .len = tag_size },
+ { .base = psa_ptr_const_to_u32(aeadtext), .len = aeadtext_size }
+ };
+
+ size_t out_len = IOVEC_LEN(out_vec);
+
+ if (aeadtext == NULL || aeadtext_size == 0)
+ out_len--;
+
+ if ((out_len == 3) && (aeadtext_length == NULL))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, out_len);
+
+ *tag_length = out_vec[1].len;
+
+ if (out_len == 3)
+ *aeadtext_length = out_vec[2].len;
+ else
+ *aeadtext_length = 0;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_verify(
+ struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *plaintext,
+ size_t plaintext_size,
+ size_t *plaintext_length,
+ const uint8_t *tag,
+ size_t tag_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_VERIFY_SID,
+ .op_handle = op_handle,
+ };
+
+ /* Sanitize the optional output */
+ if ((plaintext == NULL) && (plaintext_size != 0))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ { .base = psa_ptr_const_to_u32(tag), .len = tag_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ { .base = psa_ptr_const_to_u32(plaintext),
+ .len = plaintext_size },
+ };
+
+ size_t out_len = IOVEC_LEN(out_vec);
+
+ if (plaintext == NULL || plaintext_size == 0)
+ out_len--;
+
+ if ((out_len == 2) && (plaintext_length == NULL))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, out_len);
+
+ if (out_len == 2)
+ *plaintext_length = out_vec[1].len;
+ else
+ *plaintext_length = 0;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_aead_abort(
+ struct service_client *context,
+ uint32_t op_handle)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_AEAD_ABORT_SID,
+ .op_handle = op_handle,
+ };
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov),
+ .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline size_t crypto_caller_aead_max_update_size(
+ const struct service_client *context)
+{
+ /* Returns the maximum number of bytes that may be
+ * carried as a parameter of the mac_update operation
+ * using the packed-c encoding.
+ */
+ size_t payload_space = context->service_info.max_payload;
+ size_t overhead = iov_size;
+
+ return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+static inline size_t crypto_caller_aead_max_update_ad_size(
+ const struct service_client *context)
+{
+ /* Returns the maximum number of bytes that may be
+ * carried as a parameter of the mac_update operation
+ * using the packed-c encoding.
+ */
+ size_t payload_space = context->service_info.max_payload;
+ size_t overhead = iov_size;
+
+ return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_AEAD_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_decrypt.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_decrypt.h
new file mode 100644
index 000000000..368ba3977
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_decrypt.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_DECRYPT_H
+#define PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_DECRYPT_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_asymmetric_decrypt(
+ struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *input, size_t input_length,
+ const uint8_t *salt, size_t salt_length,
+ uint8_t *output, size_t output_size,
+ size_t *output_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ size_t in_len;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_ASYMMETRIC_DECRYPT_SID,
+ .key_id = id,
+ .alg = alg,
+ };
+
+ /* Sanitize optional input */
+ if (!salt && salt_length)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(input), .len = input_length },
+ { .base = psa_ptr_const_to_u32(salt), .len = salt_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(output), .len = output_size },
+ };
+
+
+ in_len = IOVEC_LEN(in_vec);
+ if (!salt)
+ in_len--;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ in_len, out_vec, IOVEC_LEN(out_vec));
+
+ *output_length = out_vec[0].len;
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_DECRYPT_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_encrypt.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_encrypt.h
new file mode 100644
index 000000000..9cedbe803
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_encrypt.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_ENCRYPT_H
+#define PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_ENCRYPT_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_asymmetric_encrypt(
+ struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *input, size_t input_length,
+ const uint8_t *salt, size_t salt_length,
+ uint8_t *output, size_t output_size,
+ size_t *output_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ size_t in_len;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_ASYMMETRIC_ENCRYPT_SID,
+ .key_id = id,
+ .alg = alg,
+ };
+
+ /* Sanitize optional input */
+ if (!salt && salt_length)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(input), .len = input_length },
+ { .base = psa_ptr_const_to_u32(salt), .len = salt_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(output), .len = output_size },
+ };
+
+
+ in_len = IOVEC_LEN(in_vec);
+ if (!salt)
+ in_len--;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ in_len, out_vec, IOVEC_LEN(out_vec));
+
+ *output_length = out_vec[0].len;
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_ENCRYPT_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_cipher.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_cipher.h
new file mode 100644
index 000000000..8da954d22
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_cipher.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_CIPHER_H
+#define PSA_IPC_CRYPTO_CALLER_CIPHER_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_cipher_encrypt_setup(
+ struct service_client *context,
+ uint32_t *op_handle,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_CIPHER_ENCRYPT_SETUP_SID,
+ .key_id = key,
+ .alg = alg,
+ .op_handle = *op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_decrypt_setup(
+ struct service_client *context,
+ uint32_t *op_handle,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_CIPHER_DECRYPT_SETUP_SID,
+ .key_id = key,
+ .alg = alg,
+ .op_handle = *op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_generate_iv(
+ struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *iv,
+ size_t iv_size,
+ size_t *iv_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_CIPHER_GENERATE_IV_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(iv), .len = iv_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *iv_length = out_vec[0].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_set_iv(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *iv,
+ size_t iv_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_CIPHER_SET_IV_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(iv), .len = iv_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_update(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_CIPHER_UPDATE_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(input), .len = input_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(output), .len = output_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *output_length = out_vec[0].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_finish(
+ struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_CIPHER_FINISH_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ { .base = psa_ptr_to_u32(output), .len = output_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *output_length = out_vec[1].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_abort(
+ struct service_client *context,
+ uint32_t op_handle)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_CIPHER_ABORT_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline size_t crypto_caller_cipher_max_update_size(const struct service_client *context)
+{
+ /* Returns the maximum number of bytes that may be
+ * carried as a parameter of the cipher_update operation
+ * using the ipc encoding.
+ */
+ size_t payload_space = context->service_info.max_payload;
+ size_t overhead = iov_size;
+
+ /* Allow for output to be a whole number of blocks */
+ overhead += PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE;
+
+ return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_CIPHER_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_copy_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_copy_key.h
new file mode 100644
index 000000000..f737b8e51
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_copy_key.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_COPY_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_COPY_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_copy_key(struct service_client *context,
+ psa_key_id_t source_key,
+ const psa_key_attributes_t *attributes,
+ psa_key_id_t *target_key)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_COPY_KEY_SID,
+ .key_id = source_key,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ { .base = psa_ptr_const_to_u32(attributes), .len = sizeof(psa_key_attributes_t) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(target_key), .len = sizeof(psa_key_id_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_COPY_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_destroy_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_destroy_key.h
new file mode 100644
index 000000000..5baeb2f54
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_destroy_key.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_DESTROY_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_DESTROY_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_destroy_key(struct service_client *context,
+ psa_key_id_t id)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_DESTROY_KEY_SID,
+ .key_id = id,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_DESTROY_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_key.h
new file mode 100644
index 000000000..d9a9fca2a
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_key.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021-2023 Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_EXPORT_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_EXPORT_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_export_key(struct service_client *context,
+ psa_key_id_t id,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_EXPORT_KEY_SID,
+ .key_id = id,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(data), .len = data_size }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *data_length = out_vec[0].len;
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_EXPORT_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_public_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_public_key.h
new file mode 100644
index 000000000..5f62d9cf9
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_public_key.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_EXPORT_PUBLIC_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_EXPORT_PUBLIC_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_export_public_key(struct service_client *context,
+ psa_key_id_t id,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_EXPORT_PUBLIC_KEY_SID,
+ .key_id = id,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(data), .len = data_size }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *data_length = out_vec[0].len;
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_EXPORT_PUBLIC_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_key.h
new file mode 100644
index 000000000..adb195727
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_key.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_GENERATE_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_GENERATE_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_generate_key(struct service_client *context,
+ const psa_key_attributes_t *attributes,
+ psa_key_id_t *id)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_GENERATE_KEY_SID,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ { .base = psa_ptr_const_to_u32(attributes), .len = sizeof(psa_key_attributes_t) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(id), .len = sizeof(psa_key_id_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_GENERATE_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_random.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_random.h
new file mode 100644
index 000000000..f5dd217fa
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_random.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_GENERATE_RANDOM_H
+#define PSA_IPC_CRYPTO_CALLER_GENERATE_RANDOM_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_generate_random(struct service_client *context,
+ uint8_t *output,
+ size_t output_size)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_GENERATE_RANDOM_SID,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(output), .len = output_size }
+ };
+
+ if (!output_size)
+ return PSA_SUCCESS;
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_GENERATE_RANDOM_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_key_attributes.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_key_attributes.h
new file mode 100644
index 000000000..8ae35121d
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_key_attributes.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_GET_KEY_ATTRIBUTES_H
+#define PSA_IPC_CRYPTO_CALLER_GET_KEY_ATTRIBUTES_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_get_key_attributes(
+ struct service_client *context,
+ psa_key_id_t key,
+ psa_key_attributes_t *attributes)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_GET_KEY_ATTRIBUTES_SID,
+ .key_id = key,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(attributes), .len = sizeof(psa_key_attributes_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_GET_KEY_ATTRIBUTES_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_hash.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_hash.h
new file mode 100644
index 000000000..e13f5db20
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_hash.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_HASH_H
+#define PSA_IPC_CRYPTO_CALLER_HASH_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_hash_setup(
+ struct service_client *context,
+ uint32_t *op_handle,
+ psa_algorithm_t alg)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_HASH_SETUP_SID,
+ .alg = alg,
+ .op_handle = *op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_hash_update(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *input,
+ size_t input_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_HASH_UPDATE_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(input), .len = input_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_hash_finish(
+ struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_HASH_FINISH_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ { .base = psa_ptr_to_u32(hash), .len = hash_size},
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *hash_length = out_vec[1].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_hash_abort(
+ struct service_client *context,
+ uint32_t op_handle)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_HASH_ABORT_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_hash_verify(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *hash,
+ size_t hash_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_HASH_VERIFY_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(hash), .len = hash_length},
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_hash_clone(
+ struct service_client *context,
+ uint32_t source_op_handle,
+ uint32_t *target_op_handle)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_HASH_CLONE_SID,
+ .op_handle = source_op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_to_u32(target_op_handle),
+ .len = sizeof(uint32_t) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(target_op_handle),
+ .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_hash_suspend(struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *hash_state,
+ size_t hash_state_size,
+ size_t *hash_state_length)
+{
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static inline psa_status_t crypto_caller_hash_resume(struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *hash_state,
+ size_t hash_state_length)
+{
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static inline size_t crypto_caller_hash_max_update_size(const struct service_client *context)
+{
+ /* Returns the maximum number of bytes that may be
+ * carried as a parameter of the hash_update operation
+ * using the packed-c encoding.
+ */
+ size_t payload_space = context->service_info.max_payload;
+ size_t overhead = iov_size;
+
+ return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_HASH_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_import_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_import_key.h
new file mode 100644
index 000000000..04442217e
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_import_key.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_IMPORT_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_IMPORT_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_import_key(struct service_client *context,
+ const psa_key_attributes_t *attributes,
+ const uint8_t *data, size_t data_length,
+ psa_key_id_t *id)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_IMPORT_KEY_SID,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ { .base = psa_ptr_const_to_u32(attributes), .len = sizeof(psa_key_attributes_t) },
+ { .base = psa_ptr_const_to_u32(data), .len = data_length }
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(id), .len = sizeof(psa_key_id_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PACKEDC_CRYPTO_CALLER_IMPORT_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_attributes.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_attributes.h
new file mode 100644
index 000000000..c3b9b4622
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_attributes.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_CRYPTO_CALLER_KEY_ATTRIBUTES_H
+#define PACKEDC_CRYPTO_CALLER_KEY_ATTRIBUTES_H
+
+#include <psa/crypto.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline void packedc_crypto_caller_translate_key_attributes_to_proto(
+ struct ts_crypto_key_attributes *proto_attributes,
+ const psa_key_attributes_t *psa_attributes)
+{
+ proto_attributes->type = psa_get_key_type(psa_attributes);
+ proto_attributes->key_bits = psa_get_key_bits(psa_attributes);
+ proto_attributes->lifetime = psa_get_key_lifetime(psa_attributes);
+ proto_attributes->id = psa_get_key_id(psa_attributes);
+
+ proto_attributes->policy.usage = psa_get_key_usage_flags(psa_attributes);
+ proto_attributes->policy.alg = psa_get_key_algorithm(psa_attributes);
+ }
+
+static inline void packedc_crypto_caller_translate_key_attributes_from_proto(
+ psa_key_attributes_t *psa_attributes,
+ const struct ts_crypto_key_attributes *proto_attributes)
+{
+ psa_set_key_type(psa_attributes, proto_attributes->type);
+ psa_set_key_bits(psa_attributes, proto_attributes->key_bits);
+ psa_set_key_lifetime(psa_attributes, proto_attributes->lifetime);
+
+ if (proto_attributes->lifetime == PSA_KEY_LIFETIME_PERSISTENT) {
+
+ psa_set_key_id(psa_attributes, proto_attributes->id);
+ }
+
+ psa_set_key_usage_flags(psa_attributes, proto_attributes->policy.usage);
+ psa_set_key_algorithm(psa_attributes, proto_attributes->policy.alg);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PACKEDC_CRYPTO_CALLER_KEY_ATTRIBUTES_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_derivation.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_derivation.h
new file mode 100644
index 000000000..f165db1a3
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_derivation.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_KEY_DERIVATION_H
+#define PSA_IPC_CRYPTO_CALLER_KEY_DERIVATION_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_key_derivation_setup(
+ struct service_client *context,
+ uint32_t *op_handle,
+ psa_algorithm_t alg)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_SETUP_SID,
+ .alg = alg,
+ .op_handle = *op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_get_capacity(
+ struct service_client *context,
+ const uint32_t op_handle,
+ size_t *capacity)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_GET_CAPACITY_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(capacity), .len = sizeof(uint32_t) }
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_set_capacity(
+ struct service_client *context,
+ uint32_t op_handle,
+ size_t capacity)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_SET_CAPACITY_SID,
+ .capacity = capacity,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_input_bytes(
+ struct service_client *context,
+ uint32_t op_handle,
+ psa_key_derivation_step_t step,
+ const uint8_t *data,
+ size_t data_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_INPUT_BYTES_SID,
+ .step = step,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(data), .len = data_length },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_input_key(
+ struct service_client *context,
+ uint32_t op_handle,
+ psa_key_derivation_step_t step,
+ psa_key_id_t key)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_INPUT_KEY_SID,
+ .key_id = key,
+ .step = step,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_output_bytes(
+ struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *output,
+ size_t output_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(output), .len = output_length },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_output_key(
+ struct service_client *context,
+ const psa_key_attributes_t *attributes,
+ uint32_t op_handle,
+ psa_key_id_t *key)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_OUTPUT_KEY_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(attributes),
+ .len = sizeof(psa_key_attributes_t) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(key), .len = sizeof(psa_key_id_t)},
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_abort(
+ struct service_client *context,
+ uint32_t op_handle)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_ABORT_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_key_agreement(
+ struct service_client *context,
+ uint32_t op_handle,
+ psa_key_derivation_step_t step,
+ psa_key_id_t private_key,
+ const uint8_t *peer_key,
+ size_t peer_key_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT_SID,
+ .key_id = private_key,
+ .step = step,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(peer_key),
+ .len = peer_key_length},
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_raw_key_agreement(
+ struct service_client *context,
+ psa_algorithm_t alg,
+ psa_key_id_t private_key,
+ const uint8_t *peer_key,
+ size_t peer_key_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_RAW_KEY_AGREEMENT_SID,
+ .alg = alg,
+ .key_id = private_key,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(peer_key),
+ .len = peer_key_length},
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(output), .len = output_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *output_length = out_vec[0].len;
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_KEY_DERIVATION_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_mac.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_mac.h
new file mode 100644
index 000000000..8e8053d8f
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_mac.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_MAC_H
+#define PSA_IPC_CRYPTO_CALLER_MAC_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_mac_sign_setup(
+ struct service_client *context,
+ uint32_t *op_handle,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_MAC_SIGN_SETUP_SID,
+ .key_id = key,
+ .alg = alg,
+ .op_handle = *op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_mac_verify_setup(
+ struct service_client *context,
+ uint32_t *op_handle,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_MAC_VERIFY_SETUP_SID,
+ .key_id = key,
+ .alg = alg,
+ .op_handle = *op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_mac_update(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *input,
+ size_t input_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_MAC_UPDATE_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(input), .len = input_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_mac_sign_finish(
+ struct service_client *context,
+ uint32_t op_handle,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_MAC_SIGN_FINISH_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ { .base = psa_ptr_to_u32(mac), .len = mac_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *mac_length = out_vec[1].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_mac_verify_finish(
+ struct service_client *context,
+ uint32_t op_handle,
+ const uint8_t *mac,
+ size_t mac_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_MAC_VERIFY_FINISH_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(mac), .len = mac_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_mac_abort(
+ struct service_client *context,
+ uint32_t op_handle)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_MAC_ABORT_SID,
+ .op_handle = op_handle,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+static inline size_t crypto_caller_mac_max_update_size(const struct service_client *context)
+{
+ /* Returns the maximum number of bytes that may be
+ * carried as a parameter of the mac_update operation
+ * using the packed-c encoding.
+ */
+ size_t payload_space = context->service_info.max_payload;
+ size_t overhead = iov_size;
+
+ return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_MAC_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_purge_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_purge_key.h
new file mode 100644
index 000000000..6235859f5
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_purge_key.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_CRYPTO_CALLER_PURGE_KEY_H
+#define PACKEDC_CRYPTO_CALLER_PURGE_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_purge_key(struct service_client *context,
+ psa_key_id_t id)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_PURGE_KEY_SID,
+ .key_id = id,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+
+ return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PACKEDC_CRYPTO_CALLER_PURGE_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_sign_hash.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_sign_hash.h
new file mode 100644
index 000000000..ef84458cb
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_sign_hash.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_SIGN_HASH_H
+#define PSA_IPC_CRYPTO_CALLER_SIGN_HASH_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_sign_hash(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_ASYMMETRIC_SIGN_HASH_SID,
+ .key_id = id,
+ .alg = alg,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(hash), .len = hash_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(signature), .len = signature_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *signature_length = out_vec[0].len;
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_sign_message(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = TFM_CRYPTO_ASYMMETRIC_SIGN_MESSAGE_SID,
+ .key_id = id,
+ .alg = alg,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = iov_size },
+ { .base = psa_ptr_const_to_u32(hash), .len = hash_length },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(signature), .len = signature_size },
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+ *signature_length = out_vec[0].len;
+
+ return status;
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_SIGN_HASH_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_verify_hash.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_verify_hash.h
new file mode 100644
index 000000000..0e2aef1e1
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_verify_hash.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_VERIFY_HASH_H
+#define PSA_IPC_CRYPTO_CALLER_VERIFY_HASH_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_common(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length,
+ uint32_t function_id)
+{
+ struct service_client *ipc = context;
+ struct rpc_caller_interface *caller = ipc->session->caller;
+ psa_status_t status;
+ struct psa_ipc_crypto_pack_iovec iov = {
+ .function_id = function_id,
+ .key_id = id,
+ .alg = alg,
+ };
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+ { .base = psa_ptr_const_to_u32(hash), .len = hash_length },
+ { .base = psa_ptr_const_to_u32(signature), .len = signature_length},
+ };
+
+ status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+
+ return status;
+}
+
+static inline psa_status_t crypto_caller_verify_hash(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length)
+{
+
+ return crypto_caller_common(context,id,alg,hash,hash_length,
+ signature,signature_length, TFM_CRYPTO_ASYMMETRIC_VERIFY_HASH_SID);
+}
+
+static inline psa_status_t crypto_caller_verify_message(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length)
+{
+
+ return crypto_caller_common(context,id,alg,hash,hash_length,
+ signature,signature_length, TFM_CRYPTO_ASYMMETRIC_VERIFY_MESSAGE_SID);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_VERIFY_HASH_H */
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_aead.h b/components/service/crypto/client/caller/stub/crypto_caller_aead.h
index 18aa8cecf..f3b35ea17 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_aead.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_aead.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -27,6 +27,19 @@ static inline psa_status_t crypto_caller_aead_encrypt(struct service_client *con
size_t aeadtext_size,
size_t *aeadtext_length)
{
+ (void)context;
+ (void)key;
+ (void)alg;
+ (void)nonce;
+ (void)nonce_length;
+ (void)additional_data;
+ (void)additional_data_length;
+ (void)plaintext;
+ (void)plaintext_length;
+ (void)aeadtext;
+ (void)aeadtext_size;
+ (void)aeadtext_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -43,6 +56,19 @@ static inline psa_status_t crypto_caller_aead_decrypt(struct service_client *con
size_t plaintext_size,
size_t *plaintext_length)
{
+ (void)context;
+ (void)key;
+ (void)alg;
+ (void)nonce;
+ (void)nonce_length;
+ (void)additional_data;
+ (void)additional_data_length;
+ (void)aeadtext;
+ (void)aeadtext_length;
+ (void)plaintext;
+ (void)plaintext_size;
+ (void)plaintext_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -51,6 +77,11 @@ static inline psa_status_t crypto_caller_aead_encrypt_setup(struct service_clien
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)context;
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -59,6 +90,11 @@ static inline psa_status_t crypto_caller_aead_decrypt_setup(struct service_clien
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)context;
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -68,6 +104,12 @@ static inline psa_status_t crypto_caller_aead_generate_nonce(struct service_clie
size_t nonce_size,
size_t *nonce_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)nonce;
+ (void)nonce_size;
+ (void)nonce_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -76,6 +118,11 @@ static inline psa_status_t crypto_caller_aead_set_nonce(struct service_client *c
const uint8_t *nonce,
size_t nonce_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)nonce;
+ (void)nonce_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -84,6 +131,11 @@ static inline psa_status_t crypto_caller_aead_set_lengths(struct service_client
size_t ad_length,
size_t plaintext_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)ad_length;
+ (void)plaintext_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -92,6 +144,11 @@ static inline psa_status_t crypto_caller_aead_update_ad(struct service_client *c
const uint8_t *input,
size_t input_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)input;
+ (void)input_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -103,6 +160,14 @@ static inline psa_status_t crypto_caller_aead_update(struct service_client *cont
size_t output_size,
size_t *output_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)input;
+ (void)input_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -115,6 +180,15 @@ static inline psa_status_t crypto_caller_aead_finish(struct service_client *cont
size_t tag_size,
size_t *tag_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)aeadtext;
+ (void)aeadtext_size;
+ (void)aeadtext_length;
+ (void)tag;
+ (void)tag_size;
+ (void)tag_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -126,15 +200,36 @@ static inline psa_status_t crypto_caller_aead_verify(struct service_client *cont
const uint8_t *tag,
size_t tag_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)plaintext;
+ (void)plaintext_size;
+ (void)plaintext_length;
+ (void)tag;
+ (void)tag_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
static inline psa_status_t crypto_caller_aead_abort(struct service_client *context,
uint32_t op_handle)
{
+ (void)context;
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
+static inline size_t crypto_caller_aead_max_update_ad_size(const struct service_client *context)
+{
+ return 0;
+}
+
+static inline size_t crypto_caller_aead_max_update_size(const struct service_client *context)
+{
+ return 0;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_asymmetric_decrypt.h b/components/service/crypto/client/caller/stub/crypto_caller_asymmetric_decrypt.h
index 8f64b4825..795540bbd 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_asymmetric_decrypt.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_asymmetric_decrypt.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -21,6 +21,17 @@ static inline psa_status_t crypto_caller_asymmetric_decrypt(struct service_clien
const uint8_t *salt, size_t salt_length,
uint8_t *output, size_t output_size, size_t *output_length)
{
+ (void)context;
+ (void)id;
+ (void)alg;
+ (void)input;
+ (void)input_length;
+ (void)salt;
+ (void)salt_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_asymmetric_encrypt.h b/components/service/crypto/client/caller/stub/crypto_caller_asymmetric_encrypt.h
index f75df39ab..23a2709db 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_asymmetric_encrypt.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_asymmetric_encrypt.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -21,6 +21,17 @@ static inline psa_status_t crypto_caller_asymmetric_encrypt(struct service_clien
const uint8_t *salt, size_t salt_length,
uint8_t *output, size_t output_size, size_t *output_length)
{
+ (void)context;
+ (void)id;
+ (void)alg;
+ (void)input;
+ (void)input_length;
+ (void)salt;
+ (void)salt_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_cipher.h b/components/service/crypto/client/caller/stub/crypto_caller_cipher.h
index b216b4bb6..3fc4e95c6 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_cipher.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_cipher.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,6 +19,11 @@ static inline psa_status_t crypto_caller_cipher_encrypt_setup(struct service_cli
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)context;
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -27,6 +32,11 @@ static inline psa_status_t crypto_caller_cipher_decrypt_setup(struct service_cli
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)context;
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -36,6 +46,12 @@ static inline psa_status_t crypto_caller_cipher_generate_iv(struct service_clien
size_t iv_size,
size_t *iv_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)iv;
+ (void)iv_size;
+ (void)iv_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -44,6 +60,11 @@ static inline psa_status_t crypto_caller_cipher_set_iv(struct service_client *co
const uint8_t *iv,
size_t iv_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)iv;
+ (void)iv_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -55,6 +76,14 @@ static inline psa_status_t crypto_caller_cipher_update(struct service_client *co
size_t output_size,
size_t *output_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)input;
+ (void)input_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -64,17 +93,28 @@ static inline psa_status_t crypto_caller_cipher_finish(struct service_client *co
size_t output_size,
size_t *output_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
static inline psa_status_t crypto_caller_cipher_abort(struct service_client *context,
uint32_t op_handle)
{
+ (void)context;
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
static inline size_t crypto_caller_cipher_max_update_size(struct service_client *context)
{
+ (void)context;
+
return 0;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_copy_key.h b/components/service/crypto/client/caller/stub/crypto_caller_copy_key.h
index 0fd70dc6d..8af688d95 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_copy_key.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_copy_key.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,6 +19,11 @@ static inline psa_status_t crypto_caller_copy_key(struct service_client *context
const psa_key_attributes_t *attributes,
psa_key_id_t *target_key)
{
+ (void)context;
+ (void)source_key;
+ (void)attributes;
+ (void)target_key;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_destroy_key.h b/components/service/crypto/client/caller/stub/crypto_caller_destroy_key.h
index 9233b6ca6..9e192b195 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_destroy_key.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_destroy_key.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,6 +17,9 @@ extern "C" {
static inline psa_status_t crypto_caller_destroy_key(struct service_client *context,
psa_key_id_t id)
{
+ (void)context;
+ (void)id;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_export_key.h b/components/service/crypto/client/caller/stub/crypto_caller_export_key.h
index 05d7a32ec..27b2644bd 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_export_key.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_export_key.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,6 +18,12 @@ static inline psa_status_t crypto_caller_export_key(struct service_client *conte
psa_key_id_t id,
uint8_t *data, size_t data_size, size_t *data_length)
{
+ (void)context;
+ (void)id;
+ (void)data;
+ (void)data_size;
+ (void)data_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_export_public_key.h b/components/service/crypto/client/caller/stub/crypto_caller_export_public_key.h
index fff982bbb..4d8e9a4cb 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_export_public_key.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_export_public_key.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,6 +18,12 @@ static inline psa_status_t crypto_caller_export_public_key(struct service_client
psa_key_id_t id,
uint8_t *data, size_t data_size, size_t *data_length)
{
+ (void)context;
+ (void)id;
+ (void)data;
+ (void)data_size;
+ (void)data_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_generate_key.h b/components/service/crypto/client/caller/stub/crypto_caller_generate_key.h
index ceb587b5b..4eb4133cc 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_generate_key.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_generate_key.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,6 +18,10 @@ static inline psa_status_t crypto_caller_generate_key(struct service_client *con
const psa_key_attributes_t *attributes,
psa_key_id_t *id)
{
+ (void)context;
+ (void)attributes;
+ (void)id;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_generate_random.h b/components/service/crypto/client/caller/stub/crypto_caller_generate_random.h
index c7c339ce2..a388c2917 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_generate_random.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_generate_random.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,6 +17,10 @@ extern "C" {
static inline psa_status_t crypto_caller_generate_random(struct service_client *context,
uint8_t *output, size_t output_size)
{
+ (void)context;
+ (void)output;
+ (void)output_size;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_get_key_attributes.h b/components/service/crypto/client/caller/stub/crypto_caller_get_key_attributes.h
index 4de442d74..43dbde397 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_get_key_attributes.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_get_key_attributes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,6 +18,10 @@ static inline psa_status_t crypto_caller_get_key_attributes(struct service_clien
psa_key_id_t key,
psa_key_attributes_t *attributes)
{
+ (void)context;
+ (void)key;
+ (void)attributes;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_hash.h b/components/service/crypto/client/caller/stub/crypto_caller_hash.h
index 2faee0249..6666ad3c2 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_hash.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_hash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,6 +18,10 @@ static inline psa_status_t crypto_caller_hash_setup(struct service_client *conte
uint32_t *op_handle,
psa_algorithm_t alg)
{
+ (void)context;
+ (void)op_handle;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -26,6 +30,11 @@ static inline psa_status_t crypto_caller_hash_update(struct service_client *cont
const uint8_t *input,
size_t input_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)input;
+ (void)input_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -35,12 +44,21 @@ static inline psa_status_t crypto_caller_hash_finish(struct service_client *cont
size_t hash_size,
size_t *hash_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)hash;
+ (void)hash_size;
+ (void)hash_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
static inline psa_status_t crypto_caller_hash_abort(struct service_client *context,
uint32_t op_handle)
{
+ (void)context;
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -49,6 +67,11 @@ static inline psa_status_t crypto_caller_hash_verify(struct service_client *cont
const uint8_t *hash,
size_t hash_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)hash;
+ (void)hash_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -56,28 +79,17 @@ static inline psa_status_t crypto_caller_hash_clone(struct service_client *conte
uint32_t source_op_handle,
uint32_t *target_op_handle)
{
- return PSA_ERROR_NOT_SUPPORTED;
-}
+ (void)context;
+ (void)source_op_handle;
+ (void)target_op_handle;
-static inline psa_status_t crypto_caller_hash_suspend(struct service_client *context,
- uint32_t op_handle,
- uint8_t *hash_state,
- size_t hash_state_size,
- size_t *hash_state_length)
-{
- return PSA_ERROR_NOT_SUPPORTED;
-}
-
-static inline psa_status_t crypto_caller_hash_resume(struct service_client *context,
- uint32_t op_handle,
- const uint8_t *hash_state,
- size_t hash_state_length)
-{
return PSA_ERROR_NOT_SUPPORTED;
}
static inline size_t crypto_caller_hash_max_update_size(struct service_client *context)
{
+ (void)context;
+
return 0;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_import_key.h b/components/service/crypto/client/caller/stub/crypto_caller_import_key.h
index ed41a105f..95b5d76b4 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_import_key.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_import_key.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,6 +19,12 @@ static inline psa_status_t crypto_caller_import_key(struct service_client *conte
const uint8_t *data, size_t data_length,
psa_key_id_t *id)
{
+ (void)context;
+ (void)attributes;
+ (void)data;
+ (void)data_length;
+ (void)id;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_key_derivation.h b/components/service/crypto/client/caller/stub/crypto_caller_key_derivation.h
index cb568c6c7..eddac7985 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_key_derivation.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_key_derivation.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,6 +18,10 @@ static inline psa_status_t crypto_caller_key_derivation_setup(struct service_cli
uint32_t *op_handle,
psa_algorithm_t alg)
{
+ (void)context;
+ (void)op_handle;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -25,6 +29,10 @@ static inline psa_status_t crypto_caller_key_derivation_get_capacity(struct serv
const uint32_t op_handle,
size_t *capacity)
{
+ (void)context;
+ (void)op_handle;
+ (void)capacity;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -32,6 +40,10 @@ static inline psa_status_t crypto_caller_key_derivation_set_capacity(struct serv
uint32_t op_handle,
size_t capacity)
{
+ (void)context;
+ (void)op_handle;
+ (void)capacity;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -41,6 +53,12 @@ static inline psa_status_t crypto_caller_key_derivation_input_bytes(struct servi
const uint8_t *data,
size_t data_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)step;
+ (void)data;
+ (void)data_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -49,6 +67,11 @@ static inline psa_status_t crypto_caller_key_derivation_input_key(struct service
psa_key_derivation_step_t step,
psa_key_id_t key)
{
+ (void)context;
+ (void)op_handle;
+ (void)step;
+ (void)key;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -57,6 +80,11 @@ static inline psa_status_t crypto_caller_key_derivation_output_bytes(struct serv
uint8_t *output,
size_t output_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)output;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -65,12 +93,20 @@ static inline psa_status_t crypto_caller_key_derivation_output_key(struct servic
uint32_t op_handle,
psa_key_id_t *key)
{
+ (void)context;
+ (void)attributes;
+ (void)op_handle;
+ (void)key;
+
return PSA_ERROR_NOT_SUPPORTED;
}
static inline psa_status_t crypto_caller_key_derivation_abort(struct service_client *context,
uint32_t op_handle)
{
+ (void)context;
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -81,6 +117,13 @@ static inline psa_status_t crypto_caller_key_derivation_key_agreement(struct ser
const uint8_t *peer_key,
size_t peer_key_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)step;
+ (void)private_key;
+ (void)peer_key;
+ (void)peer_key_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -93,6 +136,15 @@ static inline psa_status_t crypto_caller_raw_key_agreement(struct service_client
size_t output_size,
size_t *output_length)
{
+ (void)context;
+ (void)alg;
+ (void)private_key;
+ (void)peer_key;
+ (void)peer_key_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_mac.h b/components/service/crypto/client/caller/stub/crypto_caller_mac.h
index 6c5b870cb..ddca27d11 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_mac.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_mac.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,6 +20,11 @@ static inline psa_status_t crypto_caller_mac_sign_setup(struct service_client *c
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)context;
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -28,6 +33,11 @@ static inline psa_status_t crypto_caller_mac_verify_setup(struct service_client
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)context;
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -36,6 +46,11 @@ static inline psa_status_t crypto_caller_mac_update(struct service_client *conte
const uint8_t *input,
size_t input_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)input;
+ (void)input_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -45,6 +60,12 @@ static inline psa_status_t crypto_caller_mac_sign_finish(struct service_client *
size_t mac_size,
size_t *mac_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)mac;
+ (void)mac_size;
+ (void)mac_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -53,17 +74,27 @@ static inline psa_status_t crypto_caller_mac_verify_finish(struct service_client
const uint8_t *mac,
size_t mac_length)
{
+ (void)context;
+ (void)op_handle;
+ (void)mac;
+ (void)mac_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
static inline psa_status_t crypto_caller_mac_abort(struct service_client *context,
uint32_t op_handle)
{
+ (void)context;
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
static inline size_t crypto_caller_mac_max_update_size(struct service_client *context)
{
+ (void)context;
+
return 0;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_purge_key.h b/components/service/crypto/client/caller/stub/crypto_caller_purge_key.h
index af04af995..664432205 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_purge_key.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_purge_key.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,6 +17,9 @@ extern "C" {
static inline psa_status_t crypto_caller_purge_key(struct service_client *context,
psa_key_id_t key)
{
+ (void)context;
+ (void)key;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_sign_hash.h b/components/service/crypto/client/caller/stub/crypto_caller_sign_hash.h
index d09369a27..4b999358d 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_sign_hash.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_sign_hash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,6 +20,24 @@ static inline psa_status_t crypto_caller_sign_hash(struct service_client *contex
const uint8_t *hash, size_t hash_length,
uint8_t *signature, size_t signature_size, size_t *signature_length)
{
+ (void)context;
+ (void)id;
+ (void)alg;
+ (void)hash;
+ (void)hash_length;
+ (void)signature;
+ (void)signature_size;
+ (void)signature_length;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static inline psa_status_t crypto_caller_sign_message(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_verify_hash.h b/components/service/crypto/client/caller/stub/crypto_caller_verify_hash.h
index 20d11dcf5..15ceb4a3a 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_verify_hash.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_verify_hash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,6 +20,23 @@ static inline psa_status_t crypto_caller_verify_hash(struct service_client *cont
const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length)
{
+ (void)context;
+ (void)id;
+ (void)alg;
+ (void)hash;
+ (void)hash_length;
+ (void)signature;
+ (void)signature_length;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static inline psa_status_t crypto_caller_verify_message(struct service_client *context,
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *input, size_t input_length,
+ const uint8_t *signature, size_t signature_length)
+{
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/cpp/component.cmake b/components/service/crypto/client/cpp/component.cmake
index 9ee173841..25c59a646 100644
--- a/components/service/crypto/client/cpp/component.cmake
+++ b/components/service/crypto/client/cpp/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -11,11 +11,3 @@ endif()
target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/crypto_client.cpp"
)
-
-# The crypto client presents the PSA Crypto API and hence has a dependency on mbedcrypto for functions
-# related to setting key attributes. A minimal configuration is provided to allow a minimal library
-# to be built. This configuration may be overridden by other components that have their own
-# dependency on mbedcrypto.
-set(MBEDTLS_USER_CONFIG_FILE
- "${CMAKE_CURRENT_LIST_DIR}/config_mbedtls_user.h"
- CACHE STRING "Configuration file for Mbed TLS")
diff --git a/components/service/crypto/client/cpp/crypto_client.cpp b/components/service/crypto/client/cpp/crypto_client.cpp
index 3537c8af2..9d5609a33 100644
--- a/components/service/crypto/client/cpp/crypto_client.cpp
+++ b/components/service/crypto/client/cpp/crypto_client.cpp
@@ -5,7 +5,6 @@
*/
#include "crypto_client.h"
-#include <service/discovery/client/discovery_client.h>
#include <protocols/rpc/common/packed-c/status.h>
crypto_client::crypto_client() :
@@ -14,15 +13,10 @@ crypto_client::crypto_client() :
service_client_init(&m_client, NULL);
}
-crypto_client::crypto_client(struct rpc_caller *caller) :
+crypto_client::crypto_client(struct rpc_caller_session *session) :
m_client()
{
- service_client_init(&m_client, caller);
-
- if (caller) {
-
- discovery_client_get_service_info(&m_client);
- }
+ service_client_init(&m_client, session);
}
crypto_client::~crypto_client()
@@ -30,14 +24,9 @@ crypto_client::~crypto_client()
service_client_deinit(&m_client);
}
-void crypto_client::set_caller(struct rpc_caller *caller)
+void crypto_client::set_caller(struct rpc_caller_session *session)
{
- m_client.caller = caller;
-
- if (caller) {
-
- discovery_client_get_service_info(&m_client);
- }
+ m_client.session = session;
}
int crypto_client::err_rpc_status() const
diff --git a/components/service/crypto/client/cpp/crypto_client.h b/components/service/crypto/client/cpp/crypto_client.h
index 2a5e5b992..6792a17aa 100644
--- a/components/service/crypto/client/cpp/crypto_client.h
+++ b/components/service/crypto/client/cpp/crypto_client.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -57,7 +57,7 @@ public:
psa_key_id_t id,
uint8_t *data, size_t data_size, size_t *data_length) = 0;
- /* Sign/verify methods */
+ /* Sign/verify hash methods */
virtual psa_status_t sign_hash(
psa_key_id_t id,
psa_algorithm_t alg,
@@ -70,6 +70,19 @@ public:
const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length) = 0;
+ /* Sign/verify message methods */
+ virtual psa_status_t sign_message(
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length) = 0;
+
+ virtual psa_status_t verify_message(
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ const uint8_t *signature, size_t signature_length) = 0;
+
/* Asymmetric encrypt/decrypt */
virtual psa_status_t asymmetric_encrypt(
psa_key_id_t id,
@@ -222,10 +235,15 @@ public:
const uint8_t *peer_key, size_t peer_key_length,
uint8_t *output, size_t output_size, size_t *output_length) = 0;
+ virtual int verify_pkcs7_signature(const uint8_t *signature_cert,
+ uint64_t signature_cert_len, const uint8_t *hash,
+ uint64_t hash_len, const uint8_t *public_key_cert,
+ uint64_t public_key_cert_len) = 0;
+
protected:
crypto_client();
- crypto_client(struct rpc_caller *caller);
- void set_caller(struct rpc_caller *caller);
+ crypto_client(struct rpc_caller_session *session);
+ void set_caller(struct rpc_caller_session *session);
struct service_client m_client;
};
diff --git a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
index 4d9d8f414..aaa71f0c8 100644
--- a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
+++ b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,8 +15,8 @@ packedc_crypto_client::packedc_crypto_client() :
}
-packedc_crypto_client::packedc_crypto_client(struct rpc_caller *caller) :
- crypto_client(caller)
+packedc_crypto_client::packedc_crypto_client(struct rpc_caller_session *session) :
+ crypto_client(session)
{
}
@@ -107,6 +107,26 @@ psa_status_t packedc_crypto_client::verify_hash(
signature, signature_length);
}
+psa_status_t packedc_crypto_client::sign_message(
+ psa_key_id_t id, psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
+ return crypto_caller_sign_message(&m_client, id, alg,
+ message, message_length,
+ signature, signature_size, signature_length);
+}
+
+psa_status_t packedc_crypto_client::verify_message(
+ psa_key_id_t id, psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ const uint8_t *signature, size_t signature_length)
+{
+ return crypto_caller_verify_message(&m_client, id, alg,
+ message, message_length,
+ signature, signature_length);
+}
+
psa_status_t packedc_crypto_client::asymmetric_encrypt(
psa_key_id_t id, psa_algorithm_t alg,
const uint8_t *input, size_t input_length,
@@ -398,3 +418,13 @@ psa_status_t packedc_crypto_client::raw_key_agreement(psa_algorithm_t alg,
alg, private_key, peer_key, peer_key_length,
output, output_size, output_length);
}
+
+int packedc_crypto_client::verify_pkcs7_signature(const uint8_t *signature_cert,
+ uint64_t signature_cert_len, const uint8_t *hash,
+ uint64_t hash_len, const uint8_t *public_key_cert,
+ uint64_t public_key_cert_len)
+{
+ return crypto_caller_verify_pkcs7_signature(&m_client, signature_cert, signature_cert_len,
+ hash, hash_len, public_key_cert,
+ public_key_cert_len);
+}
diff --git a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
index 377b51d1b..8d4f60cf9 100644
--- a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
+++ b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#ifndef PACKEDC_CRYPTO_CLIENT_H
#define PACKEDC_CRYPTO_CLIENT_H
+#include "rpc_caller_session.h"
#include <service/crypto/client/cpp/crypto_client.h>
#include <protocols/service/crypto/packed-c/key_attributes.h>
@@ -17,7 +18,7 @@ class packedc_crypto_client : public crypto_client
{
public:
packedc_crypto_client();
- packedc_crypto_client(struct rpc_caller *caller);
+ packedc_crypto_client(struct rpc_caller_session *session);
virtual ~packedc_crypto_client();
/* Key lifecycle methods */
@@ -54,7 +55,7 @@ public:
psa_key_id_t id,
uint8_t *data, size_t data_size, size_t *data_length);
- /* Sign/verify methods */
+ /* Sign/verify hash methods */
psa_status_t sign_hash(
psa_key_id_t id,
psa_algorithm_t alg,
@@ -67,6 +68,19 @@ public:
const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length);
+ /* Sign/verify message methods */
+ psa_status_t sign_message(
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length);
+
+ psa_status_t verify_message(
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ const uint8_t *signature, size_t signature_length);
+
/* Asymmetric encrypt/decrypt */
psa_status_t asymmetric_encrypt(
psa_key_id_t id,
@@ -219,6 +233,9 @@ public:
const uint8_t *peer_key, size_t peer_key_length,
uint8_t *output, size_t output_size, size_t *output_length);
+ int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cert_len,
+ const uint8_t *hash, uint64_t hash_len,
+ const uint8_t *public_key_cert, uint64_t public_key_cert_len);
};
#endif /* PACKEDC_CRYPTO_CLIENT_H */
diff --git a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
index 177803511..6bae7a815 100644
--- a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
+++ b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,7 +9,6 @@
#include "protobuf_crypto_client.h"
#include <protocols/rpc/common/packed-c/status.h>
#include <service/common/serializer/protobuf/pb_helper.h>
-#include <rpc_caller.h>
#include <service/crypto/protobuf/opcodes.pb.h>
#include <service/crypto/protobuf/generate_key.pb.h>
#include <service/crypto/protobuf/destroy_key.pb.h>
@@ -30,8 +29,8 @@ protobuf_crypto_client::protobuf_crypto_client() :
}
-protobuf_crypto_client::protobuf_crypto_client(struct rpc_caller *caller) :
- crypto_client(caller)
+protobuf_crypto_client::protobuf_crypto_client(struct rpc_caller_session *session) :
+ crypto_client(session)
{
}
@@ -69,23 +68,25 @@ psa_status_t protobuf_crypto_client::generate_key(const psa_key_attributes_t *at
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_GenerateKeyIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_GENERATE_KEY, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle,
+ ts_crypto_Opcode_GENERATE_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (m_client.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -103,7 +104,7 @@ psa_status_t protobuf_crypto_client::generate_key(const psa_key_attributes_t *at
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -123,23 +124,24 @@ psa_status_t protobuf_crypto_client::destroy_key(psa_key_id_t id)
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_DestroyKeyIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_DESTROY_KEY, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle, ts_crypto_Opcode_DESTROY_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (m_client.rpc_status == RPC_SUCCESS) psa_status = service_status;
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -164,23 +166,24 @@ psa_status_t protobuf_crypto_client::import_key(const psa_key_attributes_t *attr
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_ImportKeyIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_IMPORT_KEY, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle, ts_crypto_Opcode_IMPORT_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (m_client.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -198,7 +201,7 @@ psa_status_t protobuf_crypto_client::import_key(const psa_key_attributes_t *attr
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -212,12 +215,18 @@ psa_status_t protobuf_crypto_client::copy_key(
const psa_key_attributes_t *attributes,
psa_key_id_t *target_key)
{
+ (void)source_key;
+ (void)attributes;
+ (void)target_key;
+
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t protobuf_crypto_client::purge_key(
psa_key_id_t id)
{
+ (void)id;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -225,6 +234,9 @@ psa_status_t protobuf_crypto_client::get_key_attributes(
psa_key_id_t id,
psa_key_attributes_t *attributes)
{
+ (void)id;
+ (void)attributes;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -245,23 +257,25 @@ psa_status_t protobuf_crypto_client::export_key(psa_key_id_t id,
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len,
+ PB_PACKET_LENGTH(data_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_ExportKeyIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_EXPORT_KEY, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle, ts_crypto_Opcode_EXPORT_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (m_client.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -299,7 +313,7 @@ psa_status_t protobuf_crypto_client::export_key(psa_key_id_t id,
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -321,23 +335,26 @@ psa_status_t protobuf_crypto_client::export_public_key(psa_key_id_t id,
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len,
+ PB_PACKET_LENGTH(data_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_ExportPublicKeyIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_EXPORT_PUBLIC_KEY, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle,
+ ts_crypto_Opcode_EXPORT_PUBLIC_KEY,
+ &resp_buf, &resp_len, &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (m_client.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -376,7 +393,7 @@ psa_status_t protobuf_crypto_client::export_public_key(psa_key_id_t id,
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -387,6 +404,25 @@ psa_status_t protobuf_crypto_client::sign_hash(psa_key_id_t id, psa_algorithm_t
const uint8_t *hash, size_t hash_length,
uint8_t *signature, size_t signature_size, size_t *signature_length)
{
+ return asym_sign(ts_crypto_Opcode_SIGN_HASH, id, alg,
+ hash, hash_length,
+ signature, signature_size, signature_length);
+}
+
+psa_status_t protobuf_crypto_client::sign_message(psa_key_id_t id, psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
+ return asym_sign(ts_crypto_Opcode_SIGN_MESSAGE, id, alg,
+ message, message_length,
+ signature, signature_size, signature_length);
+}
+
+psa_status_t protobuf_crypto_client::asym_sign(uint32_t opcode,
+ psa_key_id_t id, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
size_t req_len;
pb_bytes_array_t *hash_byte_array =
pb_malloc_byte_array_containing_bytes(hash, hash_length);
@@ -404,23 +440,25 @@ psa_status_t protobuf_crypto_client::sign_hash(psa_key_id_t id, psa_algorithm_t
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len,
+ PB_PACKET_LENGTH(signature_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_SignHashIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_SIGN_HASH, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle, opcode, &resp_buf, &resp_len,
+ &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (m_client.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -453,7 +491,7 @@ psa_status_t protobuf_crypto_client::sign_hash(psa_key_id_t id, psa_algorithm_t
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -462,11 +500,29 @@ psa_status_t protobuf_crypto_client::sign_hash(psa_key_id_t id, psa_algorithm_t
return psa_status;
}
-
psa_status_t protobuf_crypto_client::verify_hash(psa_key_id_t id, psa_algorithm_t alg,
const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length)
{
+ return asym_verify(ts_crypto_Opcode_VERIFY_HASH, id, alg,
+ hash, hash_length,
+ signature, signature_length);
+}
+
+psa_status_t protobuf_crypto_client::verify_message(psa_key_id_t id, psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ const uint8_t *signature, size_t signature_length)
+{
+ return asym_verify(ts_crypto_Opcode_VERIFY_MESSAGE, id, alg,
+ message, message_length,
+ signature, signature_length);
+}
+
+psa_status_t protobuf_crypto_client::asym_verify(uint32_t opcode,
+ psa_key_id_t id, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length)
+{
size_t req_len;
pb_bytes_array_t *hash_byte_array =
pb_malloc_byte_array_containing_bytes(hash, hash_length);
@@ -485,23 +541,24 @@ psa_status_t protobuf_crypto_client::verify_hash(psa_key_id_t id, psa_algorithm_
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_VerifyHashIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_VERIFY_HASH, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle, opcode, &resp_buf, &resp_len,
+ &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+ if (m_client.rpc_status == RPC_SUCCESS) psa_status = service_status;
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -519,8 +576,7 @@ psa_status_t protobuf_crypto_client::asymmetric_encrypt(psa_key_id_t id, psa_alg
size_t req_len;
pb_bytes_array_t *plaintext_byte_array =
pb_malloc_byte_array_containing_bytes(input, input_length);
- pb_bytes_array_t *salt_byte_array =
- pb_malloc_byte_array_containing_bytes(salt, salt_length);
+ pb_bytes_array_t *salt_byte_array = NULL;
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
ts_crypto_AsymmetricEncryptIn req_msg = ts_crypto_AsymmetricEncryptIn_init_default;
@@ -529,30 +585,38 @@ psa_status_t protobuf_crypto_client::asymmetric_encrypt(psa_key_id_t id, psa_alg
req_msg.id = id;
req_msg.alg = alg;
req_msg.plaintext = pb_out_byte_array(plaintext_byte_array);
- req_msg.salt = pb_out_byte_array(salt_byte_array);
+
+ if (salt && salt_length) {
+ /* Optional parameter */
+ salt_byte_array = pb_malloc_byte_array_containing_bytes(salt, salt_length);
+ req_msg.salt = pb_out_byte_array(salt_byte_array);
+ }
if (pb_get_encoded_size(&req_len, ts_crypto_AsymmetricEncryptIn_fields, &req_msg)) {
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len,
+ PB_PACKET_LENGTH(output_size));
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
+ service_status_t service_status = PSA_ERROR_GENERIC_ERROR;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_AsymmetricEncryptIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_ASYMMETRIC_ENCRYPT, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle,
+ ts_crypto_Opcode_ASYMMETRIC_ENCRYPT,
+ &resp_buf, &resp_len, &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (m_client.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -585,7 +649,7 @@ psa_status_t protobuf_crypto_client::asymmetric_encrypt(psa_key_id_t id, psa_alg
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -603,8 +667,7 @@ psa_status_t protobuf_crypto_client::asymmetric_decrypt(psa_key_id_t id, psa_alg
size_t req_len;
pb_bytes_array_t *ciphertext_byte_array =
pb_malloc_byte_array_containing_bytes(input, input_length);
- pb_bytes_array_t *salt_byte_array =
- pb_malloc_byte_array_containing_bytes(salt, salt_length);
+ pb_bytes_array_t *salt_byte_array = NULL;
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
ts_crypto_AsymmetricDecryptIn req_msg = ts_crypto_AsymmetricDecryptIn_init_default;
@@ -613,30 +676,37 @@ psa_status_t protobuf_crypto_client::asymmetric_decrypt(psa_key_id_t id, psa_alg
req_msg.id = id;
req_msg.alg = alg;
req_msg.ciphertext = pb_out_byte_array(ciphertext_byte_array);
- req_msg.salt = pb_out_byte_array(salt_byte_array);
+
+ if (salt && salt_length) {
+ /* Optional parameter */
+ salt_byte_array = pb_malloc_byte_array_containing_bytes(salt, salt_length);
+ req_msg.salt = pb_out_byte_array(salt_byte_array);
+ }
if (pb_get_encoded_size(&req_len, ts_crypto_AsymmetricDecryptIn_fields, &req_msg)) {
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len, 0);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_AsymmetricDecryptIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_ASYMMETRIC_DECRYPT, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle,
+ ts_crypto_Opcode_ASYMMETRIC_DECRYPT,
+ &resp_buf, &resp_len, &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (m_client.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -669,7 +739,7 @@ psa_status_t protobuf_crypto_client::asymmetric_decrypt(psa_key_id_t id, psa_alg
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -692,23 +762,25 @@ psa_status_t protobuf_crypto_client::generate_random(uint8_t *output, size_t out
rpc_call_handle call_handle;
uint8_t *req_buf;
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len, output_size + 8);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
pb_encode(&ostream, ts_crypto_GenerateRandomIn_fields, &req_msg);
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- ts_crypto_Opcode_GENERATE_RANDOM, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status =
+ rpc_caller_session_invoke(call_handle,
+ ts_crypto_Opcode_GENERATE_RANDOM,
+ &resp_buf, &resp_len, &service_status);
- if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (m_client.rpc_status == RPC_SUCCESS) {
- psa_status = opstatus;
+ psa_status = service_status;
if (psa_status == PSA_SUCCESS) {
@@ -738,7 +810,7 @@ psa_status_t protobuf_crypto_client::generate_random(uint8_t *output, size_t out
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
}
@@ -753,24 +825,38 @@ size_t protobuf_crypto_client::hash_max_update_size() const
psa_status_t protobuf_crypto_client::hash_setup(uint32_t *op_handle,
psa_algorithm_t alg)
{
+ (void)op_handle;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t protobuf_crypto_client::hash_update(uint32_t op_handle,
const uint8_t *input, size_t input_length)
{
+ (void)op_handle;
+ (void)input;
+ (void)input_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t protobuf_crypto_client::hash_finish(uint32_t op_handle,
uint8_t *hash, size_t hash_size, size_t *hash_length)
{
+ (void)op_handle;
+ (void)hash;
+ (void)hash_size;
+ (void)hash_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t protobuf_crypto_client::hash_abort(
uint32_t op_handle)
{
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -778,6 +864,10 @@ psa_status_t protobuf_crypto_client::hash_verify(
uint32_t op_handle,
const uint8_t *hash, size_t hash_length)
{
+ (void)op_handle;
+ (void)hash;
+ (void)hash_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -785,6 +875,9 @@ psa_status_t protobuf_crypto_client::hash_clone(
uint32_t source_op_handle,
uint32_t *target_op_handle)
{
+ (void)source_op_handle;
+ (void)target_op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -799,6 +892,10 @@ psa_status_t protobuf_crypto_client::cipher_encrypt_setup(
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -807,6 +904,10 @@ psa_status_t protobuf_crypto_client::cipher_decrypt_setup(
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -814,6 +915,11 @@ psa_status_t protobuf_crypto_client::cipher_generate_iv(
uint32_t op_handle,
uint8_t *iv, size_t iv_size, size_t *iv_length)
{
+ (void)op_handle;
+ (void)iv;
+ (void)iv_size;
+ (void)iv_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -821,6 +927,10 @@ psa_status_t protobuf_crypto_client::cipher_set_iv(
uint32_t op_handle,
const uint8_t *iv, size_t iv_length)
{
+ (void)op_handle;
+ (void)iv;
+ (void)iv_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -829,6 +939,13 @@ psa_status_t protobuf_crypto_client::cipher_update(
const uint8_t *input, size_t input_length,
uint8_t *output, size_t output_size, size_t *output_length)
{
+ (void)op_handle;
+ (void)input;
+ (void)input_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -836,12 +953,19 @@ psa_status_t protobuf_crypto_client::cipher_finish(
uint32_t op_handle,
uint8_t *output, size_t output_size, size_t *output_length)
{
+ (void)op_handle;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t protobuf_crypto_client::cipher_abort(
uint32_t op_handle)
{
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -856,6 +980,10 @@ psa_status_t protobuf_crypto_client::mac_sign_setup(
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -864,6 +992,10 @@ psa_status_t protobuf_crypto_client::mac_verify_setup(
psa_key_id_t key,
psa_algorithm_t alg)
{
+ (void)op_handle;
+ (void)key;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -871,6 +1003,10 @@ psa_status_t protobuf_crypto_client::mac_update(
uint32_t op_handle,
const uint8_t *input, size_t input_length)
{
+ (void)op_handle;
+ (void)input;
+ (void)input_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -878,6 +1014,11 @@ psa_status_t protobuf_crypto_client::mac_sign_finish(
uint32_t op_handle,
uint8_t *mac, size_t mac_size, size_t *mac_length)
{
+ (void)op_handle;
+ (void)mac;
+ (void)mac_size;
+ (void)mac_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -885,12 +1026,18 @@ psa_status_t protobuf_crypto_client::mac_verify_finish(
uint32_t op_handle,
const uint8_t *mac, size_t mac_length)
{
+ (void)op_handle;
+ (void)mac;
+ (void)mac_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t protobuf_crypto_client::mac_abort(
uint32_t op_handle)
{
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -899,6 +1046,9 @@ psa_status_t protobuf_crypto_client::key_derivation_setup(
uint32_t *op_handle,
psa_algorithm_t alg)
{
+ (void)op_handle;
+ (void)alg;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -906,6 +1056,9 @@ psa_status_t protobuf_crypto_client::key_derivation_get_capacity(
const uint32_t op_handle,
size_t *capacity)
{
+ (void)op_handle;
+ (void)capacity;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -913,6 +1066,9 @@ psa_status_t protobuf_crypto_client::key_derivation_set_capacity(
uint32_t op_handle,
size_t capacity)
{
+ (void)op_handle;
+ (void)capacity;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -921,6 +1077,11 @@ psa_status_t protobuf_crypto_client::key_derivation_input_bytes(
psa_key_derivation_step_t step,
const uint8_t *data, size_t data_length)
{
+ (void)op_handle;
+ (void)step;
+ (void)data;
+ (void)data_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -929,6 +1090,10 @@ psa_status_t protobuf_crypto_client::key_derivation_input_key(
psa_key_derivation_step_t step,
psa_key_id_t key)
{
+ (void)op_handle;
+ (void)step;
+ (void)key;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -936,6 +1101,10 @@ psa_status_t protobuf_crypto_client::key_derivation_output_bytes(
uint32_t op_handle,
uint8_t *output, size_t output_length)
{
+ (void)op_handle;
+ (void)output;
+ (void)output_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -944,12 +1113,18 @@ psa_status_t protobuf_crypto_client::key_derivation_output_key(
uint32_t op_handle,
psa_key_id_t *key)
{
+ (void)attributes;
+ (void)op_handle;
+ (void)key;
+
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t protobuf_crypto_client::key_derivation_abort(
uint32_t op_handle)
{
+ (void)op_handle;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -959,6 +1134,12 @@ psa_status_t protobuf_crypto_client::key_derivation_key_agreement(
psa_key_id_t private_key,
const uint8_t *peer_key, size_t peer_key_length)
{
+ (void)op_handle;
+ (void)step;
+ (void)private_key;
+ (void)peer_key;
+ (void)peer_key_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -967,5 +1148,29 @@ psa_status_t protobuf_crypto_client::raw_key_agreement(psa_algorithm_t alg,
const uint8_t *peer_key, size_t peer_key_length,
uint8_t *output, size_t output_size, size_t *output_length)
{
+ (void)alg;
+ (void)private_key;
+ (void)peer_key;
+ (void)peer_key_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+int protobuf_crypto_client::verify_pkcs7_signature(const uint8_t *signature_cert,
+ uint64_t signature_cert_len, const uint8_t *hash,
+ uint64_t hash_len,
+ const uint8_t *public_key_cert,
+ uint64_t public_key_cert_len)
+{
+ (void)signature_cert;
+ (void)signature_cert_len;
+ (void)hash;
+ (void)hash_len;
+ (void)public_key_cert;
+ (void)public_key_cert_len;
+
return PSA_ERROR_NOT_SUPPORTED;
}
diff --git a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
index 085d9cfaa..9ad43f710 100644
--- a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
+++ b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,6 +9,7 @@
#include <service/crypto/client/cpp/crypto_client.h>
#include <service/crypto/protobuf/key_attributes.pb.h>
+#include "rpc_caller_session.h"
/*
* A concrete crypto_client that uses the protobuf based crypto access protocol
@@ -17,7 +18,7 @@ class protobuf_crypto_client : public crypto_client
{
public:
protobuf_crypto_client();
- protobuf_crypto_client(struct rpc_caller *caller);
+ protobuf_crypto_client(struct rpc_caller_session *session);
virtual ~protobuf_crypto_client();
/* Key lifecycle methods */
@@ -54,7 +55,7 @@ public:
psa_key_id_t id,
uint8_t *data, size_t data_size, size_t *data_length);
- /* Sign/verify methods */
+ /* Sign/verify hash methods */
psa_status_t sign_hash(
psa_key_id_t id,
psa_algorithm_t alg,
@@ -67,6 +68,19 @@ public:
const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length);
+ /* Sign/verify message methods */
+ psa_status_t sign_message(
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length);
+
+ psa_status_t verify_message(
+ psa_key_id_t id,
+ psa_algorithm_t alg,
+ const uint8_t *message, size_t message_length,
+ const uint8_t *signature, size_t signature_length);
+
/* Asymmetric encrypt/decrypt */
psa_status_t asymmetric_encrypt(
psa_key_id_t id,
@@ -219,8 +233,22 @@ public:
const uint8_t *peer_key, size_t peer_key_length,
uint8_t *output, size_t output_size, size_t *output_length);
+ int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cert_len,
+ const uint8_t *hash, uint64_t hash_len,
+ const uint8_t *public_key_cert, uint64_t public_key_cert_len);
+
private:
+ psa_status_t asym_sign(uint32_t opcode,
+ psa_key_id_t id, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ uint8_t *signature, size_t signature_size, size_t *signature_length);
+
+ psa_status_t asym_verify(uint32_t opcode,
+ psa_key_id_t id, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length);
+
void translate_key_attributes(
ts_crypto_KeyAttributes &proto_attributes,
const psa_key_attributes_t &psa_attributes);
diff --git a/components/service/crypto/client/psa/component.cmake b/components/service/crypto/client/psa/component.cmake
index ad7e09c79..359db3b4a 100644
--- a/components/service/crypto/client/psa/component.cmake
+++ b/components/service/crypto/client/psa/component.cmake
@@ -31,4 +31,5 @@ target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/psa_aead.c"
"${CMAKE_CURRENT_LIST_DIR}/psa_sign_message.c"
"${CMAKE_CURRENT_LIST_DIR}/psa_verify_message.c"
+ "${CMAKE_CURRENT_LIST_DIR}/verify_pkcs7_signature.c"
)
diff --git a/components/service/crypto/client/psa/crypto_client.h b/components/service/crypto/client/psa/crypto_client.h
new file mode 100644
index 000000000..4b59bbe32
--- /dev/null
+++ b/components/service/crypto/client/psa/crypto_client.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_CLIENT_H
+#define CRYPTO_CLIENT_H
+
+#include <stdint.h>
+
+int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cert_len,
+ const uint8_t *hash, uint64_t hash_len, const uint8_t *public_key_cert,
+ uint64_t public_key_cert_len);
+
+#endif /* CRYPTO_CLIENT_H */
diff --git a/components/service/crypto/client/psa/psa_aead.c b/components/service/crypto/client/psa/psa_aead.c
index 22fd3da17..c820d2220 100644
--- a/components/service/crypto/client/psa/psa_aead.c
+++ b/components/service/crypto/client/psa/psa_aead.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,37 +8,6 @@
#include "psa_crypto_client.h"
#include "crypto_caller_selector.h"
-
-psa_status_t psa_aead_encrypt(psa_key_id_t key,
- psa_algorithm_t alg,
- const uint8_t *nonce,
- size_t nonce_length,
- const uint8_t *additional_data,
- size_t additional_data_length,
- const uint8_t *plaintext,
- size_t plaintext_length,
- uint8_t *aeadtext,
- size_t aeadtext_size,
- size_t *aeadtext_length)
-{
- return PSA_ERROR_NOT_SUPPORTED;
-}
-
-psa_status_t psa_aead_decrypt(psa_key_id_t key,
- psa_algorithm_t alg,
- const uint8_t *nonce,
- size_t nonce_length,
- const uint8_t *additional_data,
- size_t additional_data_length,
- const uint8_t *aeadtext,
- size_t aeadtext_length,
- uint8_t *plaintext,
- size_t plaintext_size,
- size_t *plaintext_length)
-{
- return PSA_ERROR_NOT_SUPPORTED;
-}
-
psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation,
psa_key_id_t key,
psa_algorithm_t alg)
@@ -105,10 +74,22 @@ psa_status_t psa_aead_update(psa_aead_operation_t *operation,
size_t output_size,
size_t *output_length)
{
- return crypto_caller_aead_update(&psa_crypto_client_instance.base,
+ psa_status_t status = crypto_caller_aead_update(&psa_crypto_client_instance.base,
operation->handle,
input, input_length,
output, output_size, output_length);
+
+ /*
+ * If too small a buffer has been provided for the output, the operation
+ * state will have been updated but the result can't be put anywhere. This
+ * is an unrecoveral condition so abort the operation.
+ */
+ if (status == PSA_ERROR_BUFFER_TOO_SMALL) {
+
+ psa_aead_abort(operation);
+ }
+
+ return status;
}
psa_status_t psa_aead_finish(psa_aead_operation_t *operation,
@@ -143,3 +124,199 @@ psa_status_t psa_aead_abort(psa_aead_operation_t *operation)
return crypto_caller_aead_abort(&psa_crypto_client_instance.base,
operation->handle);
}
+
+static psa_status_t multi_aead_update_ad(psa_aead_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length)
+{
+ psa_status_t psa_status = PSA_SUCCESS;
+ size_t max_update_size =
+ crypto_caller_aead_max_update_ad_size(&psa_crypto_client_instance.base);
+ size_t bytes_input = 0;
+
+ if (!max_update_size) {
+
+ /* Don't know the max update size so assume that the entire
+ * input and output can be handled in a single update. If
+ * this isn't true, the first aead update operation will fail
+ * safely.
+ */
+ max_update_size = input_length;
+ }
+
+ while (bytes_input < input_length) {
+
+ size_t bytes_remaining = input_length - bytes_input;
+ size_t update_len = (bytes_remaining < max_update_size) ?
+ bytes_remaining :
+ max_update_size;
+
+ psa_status = psa_aead_update_ad(operation,
+ &input[bytes_input], update_len);
+
+ if (psa_status != PSA_SUCCESS) break;
+
+ bytes_input += update_len;
+ }
+
+ return psa_status;
+}
+
+static psa_status_t multi_aead_update(psa_aead_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ psa_status_t psa_status = PSA_SUCCESS;
+ size_t max_update_size =
+ crypto_caller_aead_max_update_size(&psa_crypto_client_instance.base);
+ size_t bytes_input = 0;
+ size_t bytes_output = 0;
+
+ *output_length = 0;
+
+ if (!max_update_size) {
+
+ /* Don't know the max update size so assume that the entire
+ * input and output can be handled in a single update. If
+ * this isn't true, the first aead update operation will fail
+ * safely.
+ */
+ max_update_size = input_length;
+ }
+
+ while ((bytes_input < input_length) && (bytes_output < output_size)) {
+
+ size_t update_output_len = 0;
+ size_t bytes_remaining = input_length - bytes_input;
+ size_t update_len = (bytes_remaining < max_update_size) ?
+ bytes_remaining :
+ max_update_size;
+
+ psa_status = psa_aead_update(operation,
+ &input[bytes_input], update_len,
+ &output[bytes_output], output_size - bytes_output, &update_output_len);
+
+ if (psa_status != PSA_SUCCESS) break;
+
+ bytes_input += update_len;
+ bytes_output += update_output_len;
+ }
+
+ if (psa_status == PSA_SUCCESS) {
+
+ *output_length = bytes_output;
+ }
+
+ return psa_status;
+}
+
+psa_status_t psa_aead_encrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *plaintext,
+ size_t plaintext_length,
+ uint8_t *aeadtext,
+ size_t aeadtext_size,
+ size_t *aeadtext_length)
+{
+ psa_aead_operation_t operation = psa_aead_operation_init();
+ size_t bytes_output = 0;
+ *aeadtext_length = 0;
+
+ psa_status_t psa_status = psa_aead_encrypt_setup(&operation, key, alg);
+ if (psa_status != PSA_SUCCESS) return psa_status;
+
+ if ((psa_status = psa_aead_set_lengths(&operation, additional_data_length, plaintext_length),
+ psa_status == PSA_SUCCESS) &&
+ (psa_status = psa_aead_set_nonce(&operation, nonce, nonce_length),
+ psa_status == PSA_SUCCESS) &&
+ (psa_status = multi_aead_update_ad(&operation, additional_data, additional_data_length),
+ psa_status == PSA_SUCCESS) &&
+ (psa_status = multi_aead_update(&operation, plaintext, plaintext_length,
+ aeadtext, aeadtext_size, &bytes_output),
+ psa_status == PSA_SUCCESS))
+ {
+ size_t remaining_aead_len = 0;
+ size_t tag_len = 0;
+
+ psa_status = psa_aead_finish(&operation,
+ NULL, 0, &remaining_aead_len,
+ &aeadtext[bytes_output], aeadtext_size - bytes_output, &tag_len);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ *aeadtext_length = bytes_output + remaining_aead_len + tag_len;
+ }
+ else {
+
+ psa_aead_abort(&operation);
+ }
+ }
+ else {
+
+ psa_aead_abort(&operation);
+ }
+
+ return psa_status;
+}
+
+psa_status_t psa_aead_decrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *aeadtext,
+ size_t aeadtext_length,
+ uint8_t *plaintext,
+ size_t plaintext_size,
+ size_t *plaintext_length)
+{
+ psa_aead_operation_t operation = psa_aead_operation_init();
+ size_t bytes_output = 0;
+ *plaintext_length = 0;
+
+ psa_status_t psa_status = psa_aead_decrypt_setup(&operation, key, alg);
+ if (psa_status != PSA_SUCCESS) return psa_status;
+
+ size_t tag_len = PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
+ size_t ciphertext_len = (aeadtext_length > tag_len) ? aeadtext_length - tag_len : 0;
+
+ if ((psa_status = psa_aead_set_lengths(&operation, additional_data_length, ciphertext_len),
+ psa_status == PSA_SUCCESS) &&
+ (psa_status = psa_aead_set_nonce(&operation, nonce, nonce_length),
+ psa_status == PSA_SUCCESS) &&
+ (psa_status = multi_aead_update_ad(&operation, additional_data, additional_data_length),
+ psa_status == PSA_SUCCESS) &&
+ (psa_status = multi_aead_update(&operation, aeadtext, ciphertext_len,
+ plaintext, plaintext_size, &bytes_output),
+ psa_status == PSA_SUCCESS))
+ {
+ size_t remaining_plaintext_len = 0;
+
+ psa_status = psa_aead_verify(&operation,
+ NULL, 0, &remaining_plaintext_len,
+ &aeadtext[bytes_output], aeadtext_length - bytes_output);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ *plaintext_length = bytes_output + remaining_plaintext_len;
+ }
+ else {
+
+ psa_aead_abort(&operation);
+ }
+ }
+ else {
+
+ psa_aead_abort(&operation);
+ }
+
+ return psa_status;
+}
diff --git a/components/service/crypto/client/psa/psa_cipher.c b/components/service/crypto/client/psa/psa_cipher.c
index 70836ea6b..d6e65400b 100644
--- a/components/service/crypto/client/psa/psa_cipher.c
+++ b/components/service/crypto/client/psa/psa_cipher.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,11 +8,16 @@
#include "psa_crypto_client.h"
#include "crypto_caller_selector.h"
-
psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation,
psa_key_id_t key,
psa_algorithm_t alg)
{
+ if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
+ return psa_crypto_client_instance.init_status;
+
+ if (operation->handle)
+ return PSA_ERROR_BAD_STATE;
+
return crypto_caller_cipher_encrypt_setup(&psa_crypto_client_instance.base,
&operation->handle,
key, alg);
@@ -22,6 +27,12 @@ psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation,
psa_key_id_t key,
psa_algorithm_t alg)
{
+ if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
+ return psa_crypto_client_instance.init_status;
+
+ if (operation->handle)
+ return PSA_ERROR_BAD_STATE;
+
return crypto_caller_cipher_decrypt_setup(&psa_crypto_client_instance.base,
&operation->handle,
key, alg);
@@ -100,7 +111,13 @@ static psa_status_t multi_cipher_update(psa_cipher_operation_t *operation,
max_update_size = input_length;
}
- while ((bytes_input < input_length) && (bytes_output < output_size)) {
+ while (bytes_input < input_length) {
+
+ if (bytes_output >= output_size) {
+
+ psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+ break;
+ }
size_t update_output_len = 0;
size_t bytes_remaining = input_length - bytes_input;
@@ -112,11 +129,8 @@ static psa_status_t multi_cipher_update(psa_cipher_operation_t *operation,
&input[bytes_input], update_len,
&output[bytes_output], output_size - bytes_output, &update_output_len);
- if (psa_status != PSA_SUCCESS) {
-
- psa_cipher_abort(operation);
+ if (psa_status != PSA_SUCCESS)
break;
- }
bytes_input += update_len;
bytes_output += update_output_len;
@@ -135,10 +149,13 @@ static psa_status_t multi_cipher_update(psa_cipher_operation_t *operation,
*output_length = bytes_output + finish_output_len;
}
+ else {
+
+ psa_cipher_abort(operation);
+ }
}
else {
- psa_cipher_abort(operation);
psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
}
}
@@ -159,9 +176,31 @@ psa_status_t psa_cipher_encrypt(psa_key_id_t key,
if (psa_status == PSA_SUCCESS) {
- psa_status = multi_cipher_update(&operation,
- input, input_length,
- output, output_size, output_length);
+ size_t ciphertext_len = 0;
+ size_t iv_len = 0;
+
+ psa_status = psa_cipher_generate_iv(&operation, output, output_size, &iv_len);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ if (iv_len <= output_size) {
+
+ psa_status = multi_cipher_update(&operation,
+ input, input_length,
+ &output[iv_len], output_size - iv_len, &ciphertext_len);
+
+ *output_length = iv_len + ciphertext_len;
+ }
+ else {
+
+ psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ }
+
+ if (psa_status != PSA_SUCCESS) {
+
+ psa_cipher_abort(&operation);
+ }
}
return psa_status;
@@ -175,14 +214,41 @@ psa_status_t psa_cipher_decrypt(psa_key_id_t key,
size_t output_size,
size_t *output_length)
{
- psa_cipher_operation_t operation = psa_cipher_operation_init();
- psa_status_t psa_status = psa_cipher_decrypt_setup(&operation, key, alg);
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_status_t psa_status = psa_get_key_attributes(key, &attributes);
if (psa_status == PSA_SUCCESS) {
- psa_status = multi_cipher_update(&operation,
- input, input_length,
- output, output_size, output_length);
+ psa_cipher_operation_t operation = psa_cipher_operation_init();
+ psa_status = psa_cipher_decrypt_setup(&operation, key, alg);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ size_t iv_len = PSA_CIPHER_IV_LENGTH(psa_get_key_type(&attributes), alg);
+
+ if (input_length >= iv_len) {
+
+ psa_status = psa_cipher_set_iv(&operation, input, iv_len);
+
+ if (psa_status == PSA_SUCCESS) {
+
+ psa_status = multi_cipher_update(&operation,
+ &input[iv_len], input_length - iv_len,
+ output, output_size, output_length);
+ }
+ }
+ else {
+
+ psa_status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (psa_status != PSA_SUCCESS) {
+
+ psa_cipher_abort(&operation);
+ }
+ }
+
+ psa_reset_key_attributes(&attributes);
}
return psa_status;
diff --git a/components/service/crypto/client/psa/psa_crypto_client.c b/components/service/crypto/client/psa/psa_crypto_client.c
index 1c0e05570..e42d37a5e 100644
--- a/components/service/crypto/client/psa/psa_crypto_client.c
+++ b/components/service/crypto/client/psa/psa_crypto_client.c
@@ -9,7 +9,7 @@
struct psa_crypto_client psa_crypto_client_instance = {
- .base.caller = NULL,
+ .base.session = NULL,
/* To conform to PSA API, psa_crypto_init needs to be called.
* This state variable is used enforces this.
@@ -20,17 +20,15 @@ struct psa_crypto_client psa_crypto_client_instance = {
psa_status_t psa_crypto_init(void) {
/* Must be called after psa_crypto_client_init */
- if (psa_crypto_client_instance.base.caller) {
-
+ if (psa_crypto_client_instance.base.session)
psa_crypto_client_instance.init_status = PSA_SUCCESS;
- }
return psa_crypto_client_instance.init_status;
}
-psa_status_t psa_crypto_client_init(struct rpc_caller *caller)
+psa_status_t psa_crypto_client_init(struct rpc_caller_session *session)
{
- return service_client_init(&psa_crypto_client_instance.base, caller);
+ return service_client_init(&psa_crypto_client_instance.base, session);
}
void psa_crypto_client_deinit(void)
diff --git a/components/service/crypto/client/psa/psa_crypto_client.h b/components/service/crypto/client/psa/psa_crypto_client.h
index fbf6046a1..00415013b 100644
--- a/components/service/crypto/client/psa/psa_crypto_client.h
+++ b/components/service/crypto/client/psa/psa_crypto_client.h
@@ -39,7 +39,7 @@ extern struct psa_crypto_client psa_crypto_client_instance;
*
* @return A status indicating the success/failure of the operation
*/
-psa_status_t psa_crypto_client_init(struct rpc_caller *caller);
+psa_status_t psa_crypto_client_init(struct rpc_caller_session *session);
/**
* @brief De-initialises the single psa crypto client
diff --git a/components/service/crypto/client/psa/psa_hash.c b/components/service/crypto/client/psa/psa_hash.c
index 7005c3900..2e3db0e97 100644
--- a/components/service/crypto/client/psa/psa_hash.c
+++ b/components/service/crypto/client/psa/psa_hash.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,6 +14,9 @@ psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
return psa_crypto_client_instance.init_status;
+ if (operation->handle)
+ return PSA_ERROR_BAD_STATE;
+
return crypto_caller_hash_setup(&psa_crypto_client_instance.base,
&operation->handle, alg);
}
@@ -55,6 +58,9 @@ psa_status_t psa_hash_verify(psa_hash_operation_t *operation,
psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation,
psa_hash_operation_t *target_operation)
{
+ if (target_operation->handle)
+ return PSA_ERROR_BAD_STATE;
+
return crypto_caller_hash_clone(&psa_crypto_client_instance.base,
source_operation->handle,
&target_operation->handle);
@@ -65,6 +71,11 @@ psa_status_t psa_hash_suspend(psa_hash_operation_t *operation,
size_t hash_state_size,
size_t *hash_state_length)
{
+ (void)operation;
+ (void)hash_state;
+ (void)hash_state_size;
+ (void)hash_state_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -72,6 +83,10 @@ psa_status_t psa_hash_resume(psa_hash_operation_t *operation,
const uint8_t *hash_state,
size_t hash_state_length)
{
+ (void)operation;
+ (void)hash_state;
+ (void)hash_state_length;
+
return PSA_ERROR_NOT_SUPPORTED;
}
@@ -131,6 +146,11 @@ psa_status_t psa_hash_compare(psa_algorithm_t alg,
if (psa_status == PSA_SUCCESS) {
psa_status = psa_hash_verify(&operation, hash, hash_length);
+
+ if (psa_status != PSA_SUCCESS) {
+
+ psa_hash_abort(&operation);
+ }
}
return psa_status;
@@ -149,6 +169,11 @@ psa_status_t psa_hash_compute(psa_algorithm_t alg,
if (psa_status == PSA_SUCCESS) {
psa_status = psa_hash_finish(&operation, hash, hash_size, hash_length);
+
+ if (psa_status != PSA_SUCCESS) {
+
+ psa_hash_abort(&operation);
+ }
}
return psa_status;
diff --git a/components/service/crypto/client/psa/psa_mac.c b/components/service/crypto/client/psa/psa_mac.c
index 5efa1c4df..a3db86444 100644
--- a/components/service/crypto/client/psa/psa_mac.c
+++ b/components/service/crypto/client/psa/psa_mac.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -16,6 +16,9 @@ psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation,
if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
return psa_crypto_client_instance.init_status;
+ if (operation->handle)
+ return PSA_ERROR_BAD_STATE;
+
return crypto_caller_mac_sign_setup(&psa_crypto_client_instance.base,
&operation->handle,
key, alg);
@@ -28,7 +31,10 @@ psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation,
if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
return psa_crypto_client_instance.init_status;
- return crypto_caller_mac_sign_setup(&psa_crypto_client_instance.base,
+ if (operation->handle)
+ return PSA_ERROR_BAD_STATE;
+
+ return crypto_caller_mac_verify_setup(&psa_crypto_client_instance.base,
&operation->handle,
key, alg);
}
@@ -123,6 +129,11 @@ psa_status_t psa_mac_verify(psa_key_id_t key,
if (psa_status == PSA_SUCCESS) {
psa_status = psa_mac_verify_finish(&operation, mac, mac_length);
+
+ if (psa_status != PSA_SUCCESS) {
+
+ psa_mac_abort(&operation);
+ }
}
return psa_status;
@@ -147,6 +158,11 @@ psa_status_t psa_mac_compute(psa_key_id_t key,
if (psa_status == PSA_SUCCESS) {
psa_status = psa_mac_sign_finish(&operation, mac, mac_size, mac_length);
+
+ if (psa_status != PSA_SUCCESS) {
+
+ psa_mac_abort(&operation);
+ }
}
return psa_status;
diff --git a/components/service/crypto/client/psa/psa_sign_message.c b/components/service/crypto/client/psa/psa_sign_message.c
index dc2f7e80c..b64462536 100644
--- a/components/service/crypto/client/psa/psa_sign_message.c
+++ b/components/service/crypto/client/psa/psa_sign_message.c
@@ -1,13 +1,15 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <psa/crypto.h>
+#include "psa_crypto_client.h"
+#include "crypto_caller_selector.h"
psa_status_t psa_sign_message(
- psa_key_id_t key,
+ psa_key_id_t id,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
@@ -15,19 +17,11 @@ psa_status_t psa_sign_message(
size_t signature_size,
size_t *signature_length)
{
- size_t hash_len;
- uint8_t hash[PSA_HASH_MAX_SIZE];
+ if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
+ return psa_crypto_client_instance.init_status;
- psa_status_t psa_status = psa_hash_compute(PSA_ALG_SIGN_GET_HASH(alg),
+ return crypto_caller_sign_message(&psa_crypto_client_instance.base,
+ id, alg,
input, input_length,
- hash, sizeof(hash), &hash_len);
-
- if (psa_status == PSA_SUCCESS) {
-
- psa_status = psa_sign_hash(key, alg,
- hash, hash_len,
- signature, signature_size, signature_length);
- }
-
- return psa_status;
+ signature, signature_size, signature_length);
}
diff --git a/components/service/crypto/client/psa/psa_verify_message.c b/components/service/crypto/client/psa/psa_verify_message.c
index d0fbc7c8c..57c2c5e84 100644
--- a/components/service/crypto/client/psa/psa_verify_message.c
+++ b/components/service/crypto/client/psa/psa_verify_message.c
@@ -1,32 +1,26 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <psa/crypto.h>
+#include "psa_crypto_client.h"
+#include "crypto_caller_selector.h"
psa_status_t psa_verify_message(
- psa_key_id_t key,
+ psa_key_id_t id,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
const uint8_t * signature,
size_t signature_length)
{
- size_t hash_len;
- uint8_t hash[PSA_HASH_MAX_SIZE];
+ if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
+ return psa_crypto_client_instance.init_status;
- psa_status_t psa_status = psa_hash_compute(PSA_ALG_SIGN_GET_HASH(alg),
+ return crypto_caller_verify_message(&psa_crypto_client_instance.base,
+ id, alg,
input, input_length,
- hash, sizeof(hash), &hash_len);
-
- if (psa_status == PSA_SUCCESS) {
-
- psa_status = psa_verify_hash(key, alg,
- hash, hash_len,
- signature, signature_length);
- }
-
- return psa_status;
+ signature, signature_length);
}
diff --git a/components/service/crypto/client/psa/verify_pkcs7_signature.c b/components/service/crypto/client/psa/verify_pkcs7_signature.c
new file mode 100644
index 000000000..e329f3423
--- /dev/null
+++ b/components/service/crypto/client/psa/verify_pkcs7_signature.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "crypto_caller_selector.h"
+#include "crypto_client.h"
+#include "psa_crypto_client.h"
+
+int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cert_len,
+ const uint8_t *hash, uint64_t hash_len, const uint8_t *public_key_cert,
+ uint64_t public_key_cert_len)
+{
+ if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
+ return psa_crypto_client_instance.init_status;
+
+ return crypto_caller_verify_pkcs7_signature(&psa_crypto_client_instance.base,
+ signature_cert, signature_cert_len, hash,
+ hash_len, public_key_cert, public_key_cert_len);
+}
diff --git a/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp b/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
index b5a7ca04a..614647754 100644
--- a/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
+++ b/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
@@ -1,13 +1,16 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "standalone_crypto_client.h"
+#include "service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
+#include "service/crypto/provider/crypto_uuid.h"
#include <service/crypto/factory/crypto_provider_factory.h>
#include <service/crypto/backend/mbedcrypto/mbedcrypto_backend.h>
#include <service/secure_storage/backend/secure_flash_store/secure_flash_store.h>
+#include <service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.h>
standalone_crypto_client::standalone_crypto_client() :
test_crypto_client(),
@@ -16,7 +19,8 @@ standalone_crypto_client::standalone_crypto_client() :
m_storage_client(),
m_crypto_caller(),
m_storage_caller(),
- m_dummy_storage_caller()
+ m_crypto_session(),
+ m_storage_session()
{
}
@@ -31,42 +35,55 @@ bool standalone_crypto_client::init()
bool should_do = test_crypto_client::init();
if (should_do) {
-
- struct rpc_caller *storage_caller;
+ const struct rpc_uuid storage_uuid = { .uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID };
+ const struct rpc_uuid crypto_uuid = { .uuid = TS_PSA_CRYPTO_PROTOBUF_SERVICE_UUID };
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
if (!is_fault_injected(FAILED_TO_DISCOVER_SECURE_STORAGE)) {
/* Establish rpc session with storage provider */
- struct storage_backend *storage_backend = sfs_init();
- struct rpc_interface *storage_ep = secure_storage_provider_init(&m_storage_provider,
- storage_backend);
- storage_caller = direct_caller_init_default(&m_storage_caller, storage_ep);
- }
- else {
+ struct storage_backend *storage_backend = sfs_init(sfs_flash_ram_instance());
+ struct rpc_service_interface *storage_service =
+ secure_storage_provider_init(&m_storage_provider, storage_backend, &storage_uuid);
+ rpc_status = direct_caller_init(&m_storage_caller, storage_service);
+ } else {
/*
* Missing storage service fault injected. To allow a somewhat viable
* crypto service to be started, use a dummy _caller that will safely
* terminate storage calls with an appropriate error.
*/
- storage_caller = dummy_caller_init(&m_dummy_storage_caller,
- TS_RPC_CALL_ACCEPTED, PSA_ERROR_STORAGE_FAILURE);
+ rpc_status = dummy_caller_init(&m_storage_caller, RPC_SUCCESS, PSA_ERROR_STORAGE_FAILURE);
}
- struct rpc_interface *crypto_iface = NULL;
+ if (rpc_status != RPC_SUCCESS)
+ return false;
+
+ rpc_status = rpc_caller_session_find_and_open(&m_storage_session, &m_storage_caller,
+ &storage_uuid, 4096);
+ if (rpc_status != RPC_SUCCESS)
+ return false;
+
+ struct rpc_service_interface *crypto_iface = NULL;
struct storage_backend *client_storage_backend =
- secure_storage_client_init(&m_storage_client, storage_caller);
+ secure_storage_client_init(&m_storage_client, &m_storage_session);
if (mbedcrypto_backend_init(client_storage_backend, 0) == PSA_SUCCESS) {
- m_crypto_provider = crypto_provider_factory_create();
+ m_crypto_provider = crypto_protobuf_provider_factory_create();
crypto_iface = service_provider_get_rpc_interface(&m_crypto_provider->base_provider);
}
- struct rpc_caller *crypto_caller = direct_caller_init_default(&m_crypto_caller, crypto_iface);
- rpc_caller_set_encoding_scheme(crypto_caller, TS_RPC_ENCODING_PROTOBUF);
+ rpc_status = direct_caller_init(&m_crypto_caller, crypto_iface);
+ if (rpc_status != RPC_SUCCESS)
+ return false;
+
+ rpc_status = rpc_caller_session_find_and_open(&m_crypto_session, &m_crypto_caller,
+ &crypto_uuid, 4096);
+ if (rpc_status != RPC_SUCCESS)
+ return false;
- crypto_client::set_caller(crypto_caller);
+ crypto_client::set_caller(&m_crypto_session);
}
return should_do;
@@ -82,6 +99,9 @@ bool standalone_crypto_client::deinit()
secure_storage_provider_deinit(&m_storage_provider);
secure_storage_client_deinit(&m_storage_client);
+ rpc_caller_session_close(&m_storage_session);
+ rpc_caller_session_close(&m_crypto_session);
+
direct_caller_deinit(&m_storage_caller);
direct_caller_deinit(&m_crypto_caller);
}
diff --git a/components/service/crypto/client/test/standalone/standalone_crypto_client.h b/components/service/crypto/client/test/standalone/standalone_crypto_client.h
index 8df086114..c6d9ace32 100644
--- a/components/service/crypto/client/test/standalone/standalone_crypto_client.h
+++ b/components/service/crypto/client/test/standalone/standalone_crypto_client.h
@@ -46,9 +46,10 @@ private:
struct crypto_provider *m_crypto_provider;
struct secure_storage_provider m_storage_provider;
struct secure_storage_client m_storage_client;
- struct direct_caller m_crypto_caller;
- struct direct_caller m_storage_caller;
- struct dummy_caller m_dummy_storage_caller;
+ struct rpc_caller_interface m_crypto_caller;
+ struct rpc_caller_interface m_storage_caller;
+ struct rpc_caller_session m_crypto_session;
+ struct rpc_caller_session m_storage_session;
};
#endif /* STANDALONE_CRYPTO_CLIENT_H */
diff --git a/components/service/crypto/factory/crypto_provider_factory.h b/components/service/crypto/factory/crypto_provider_factory.h
index f4b14917d..f5b878742 100644
--- a/components/service/crypto/factory/crypto_provider_factory.h
+++ b/components/service/crypto/factory/crypto_provider_factory.h
@@ -28,6 +28,8 @@ extern "C" {
*/
struct crypto_provider *crypto_provider_factory_create(void);
+struct crypto_provider *crypto_protobuf_provider_factory_create(void);
+
/**
* \brief Destroys a created crypto provider
*
diff --git a/components/service/crypto/factory/full/crypto_provider_factory.c b/components/service/crypto/factory/full/crypto_provider_factory.c
index 2d926eb67..45af9aad1 100644
--- a/components/service/crypto/factory/full/crypto_provider_factory.c
+++ b/components/service/crypto/factory/full/crypto_provider_factory.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -17,8 +17,8 @@
#include <service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.h>
#include <service/crypto/provider/extension/mac/mac_provider.h>
#include <service/crypto/provider/extension/mac/serializer/packed-c/packedc_mac_provider_serializer.h>
-#include <service/discovery/provider/discovery_provider.h>
-#include <service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.h>
+#include <service/crypto/provider/extension/aead/aead_provider.h>
+#include <service/crypto/provider/extension/aead/serializer/packed-c/packedc_aead_provider_serializer.h>
/**
* A crypto provider factory that constucts a crypto provider
@@ -30,11 +30,12 @@
static struct full_crypto_provider
{
struct crypto_provider crypto_provider;
+ struct crypto_provider crypto_provider_protobuf;
struct hash_provider hash_provider;
struct cipher_provider cipher_provider;
struct key_derivation_provider key_derivation_provider;
struct mac_provider mac_provider;
-
+ struct aead_provider aead_provider;
} instance;
struct crypto_provider *crypto_provider_factory_create(void)
@@ -42,17 +43,8 @@ struct crypto_provider *crypto_provider_factory_create(void)
/**
* Initialize the core crypto provider
*/
- crypto_provider_init(&instance.crypto_provider);
-
- /* Register serializers for the core crypto provider */
- crypto_provider_register_serializer(&instance.crypto_provider,
- TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
- crypto_provider_register_serializer(&instance.crypto_provider,
- TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
-
- /* Register serializer for the associated discovery provider */
- discovery_provider_register_serializer(&instance.crypto_provider.discovery_provider,
- TS_RPC_ENCODING_PACKED_C, packedc_discovery_provider_serializer_instance());
+ crypto_provider_init(&instance.crypto_provider, TS_RPC_ENCODING_PACKED_C,
+ packedc_crypto_provider_serializer_instance());
/**
* Extend with hash operations
@@ -82,7 +74,8 @@ struct crypto_provider *crypto_provider_factory_create(void)
key_derivation_provider_init(&instance.key_derivation_provider);
key_derivation_provider_register_serializer(&instance.key_derivation_provider,
- TS_RPC_ENCODING_PACKED_C, packedc_key_derivation_provider_serializer_instance());
+ TS_RPC_ENCODING_PACKED_C,
+ packedc_key_derivation_provider_serializer_instance());
crypto_provider_extend(&instance.crypto_provider,
&instance.key_derivation_provider.base_provider);
@@ -98,9 +91,28 @@ struct crypto_provider *crypto_provider_factory_create(void)
crypto_provider_extend(&instance.crypto_provider,
&instance.mac_provider.base_provider);
+ /**
+ * Extend with aead operations
+ */
+ aead_provider_init(&instance.aead_provider);
+
+ aead_provider_register_serializer(&instance.aead_provider,
+ TS_RPC_ENCODING_PACKED_C, packedc_aead_provider_serializer_instance());
+
+ crypto_provider_extend(&instance.crypto_provider,
+ &instance.aead_provider.base_provider);
+
return &instance.crypto_provider;
}
+struct crypto_provider *crypto_protobuf_provider_factory_create(void)
+{
+ crypto_provider_init(&instance.crypto_provider_protobuf, TS_RPC_ENCODING_PROTOBUF,
+ pb_crypto_provider_serializer_instance());
+
+ return &instance.crypto_provider_protobuf;
+}
+
/**
* \brief Destroys a created crypto provider
*
diff --git a/components/service/crypto/include/psa/crypto_client_struct.h b/components/service/crypto/include/psa/crypto_client_struct.h
index abd420c82..1f68aba21 100644
--- a/components/service/crypto/include/psa/crypto_client_struct.h
+++ b/components/service/crypto/include/psa/crypto_client_struct.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -31,12 +31,12 @@ extern "C" {
* data structure internally. */
struct psa_client_key_attributes_s
{
+ uint16_t type;
+ uint16_t bits;
uint32_t lifetime;
- uint32_t id;
- uint32_t alg;
+ psa_key_id_t id;
uint32_t usage;
- size_t bits;
- uint16_t type;
+ uint32_t alg;
};
#define PSA_CLIENT_KEY_ATTRIBUTES_INIT {0, 0, 0, 0, 0, 0}
diff --git a/components/service/crypto/include/psa/crypto_sizes.h b/components/service/crypto/include/psa/crypto_sizes.h
index 7a0149bbc..30aa102da 100644
--- a/components/service/crypto/include/psa/crypto_sizes.h
+++ b/components/service/crypto/include/psa/crypto_sizes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -81,7 +81,7 @@
#define PSA_HASH_MAX_SIZE 64
#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 128
#else
-#define PSA_HASH_MAX_SIZE 32
+#define PSA_HASH_MAX_SIZE 64
#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64
#endif
diff --git a/components/service/crypto/include/psa/crypto_struct.h b/components/service/crypto/include/psa/crypto_struct.h
index 1bc55e375..97cdf5528 100644
--- a/components/service/crypto/include/psa/crypto_struct.h
+++ b/components/service/crypto/include/psa/crypto_struct.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -155,9 +155,19 @@ static inline psa_key_lifetime_t psa_get_key_lifetime(
return( attributes->lifetime );
}
+static inline void psa_extend_key_usage_flags( psa_key_usage_t *usage_flags )
+{
+ if( *usage_flags & PSA_KEY_USAGE_SIGN_HASH )
+ *usage_flags |= PSA_KEY_USAGE_SIGN_MESSAGE;
+
+ if( *usage_flags & PSA_KEY_USAGE_VERIFY_HASH )
+ *usage_flags |= PSA_KEY_USAGE_VERIFY_MESSAGE;
+}
+
static inline void psa_set_key_usage_flags(psa_key_attributes_t *attributes,
psa_key_usage_t usage_flags)
{
+ psa_extend_key_usage_flags( &usage_flags );
attributes->usage = usage_flags;
}
diff --git a/components/service/crypto/provider/crypto_provider.c b/components/service/crypto/provider/crypto_provider.c
index d0fc7cac2..8992b93c6 100644
--- a/components/service/crypto/provider/crypto_provider.c
+++ b/components/service/crypto/provider/crypto_provider.c
@@ -1,100 +1,105 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <stdint.h>
-#include <stdlib.h>
-#include <protocols/service/crypto/packed-c/opcodes.h>
-#include <service/crypto/provider/crypto_provider.h>
+#include <mbedtls/build_info.h>
+#include <mbedtls/pkcs7.h>
+#include <mbedtls/x509_crt.h>
#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
#include <psa/crypto.h>
+#include <service/crypto/provider/crypto_provider.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "crypto_uuid.h"
/* Service request handlers */
-static rpc_status_t generate_key_handler(void *context, struct call_req* req);
-static rpc_status_t destroy_key_handler(void *context, struct call_req* req);
-static rpc_status_t export_key_handler(void *context, struct call_req* req);
-static rpc_status_t export_public_key_handler(void *context, struct call_req* req);
-static rpc_status_t import_key_handler(void *context, struct call_req* req);
-static rpc_status_t sign_hash_handler(void *context, struct call_req* req);
-static rpc_status_t verify_hash_handler(void *context, struct call_req* req);
-static rpc_status_t asymmetric_decrypt_handler(void *context, struct call_req* req);
-static rpc_status_t asymmetric_encrypt_handler(void *context, struct call_req* req);
-static rpc_status_t generate_random_handler(void *context, struct call_req* req);
-static rpc_status_t copy_key_handler(void *context, struct call_req* req);
-static rpc_status_t purge_key_handler(void *context, struct call_req* req);
-static rpc_status_t get_key_attributes_handler(void *context, struct call_req* req);
+static rpc_status_t generate_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t destroy_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t export_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t export_public_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t import_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t asymmetric_sign_handler(void *context, struct rpc_request *req);
+static rpc_status_t asymmetric_verify_handler(void *context, struct rpc_request *req);
+static rpc_status_t asymmetric_decrypt_handler(void *context, struct rpc_request *req);
+static rpc_status_t asymmetric_encrypt_handler(void *context, struct rpc_request *req);
+static rpc_status_t generate_random_handler(void *context, struct rpc_request *req);
+static rpc_status_t copy_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t purge_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t get_key_attributes_handler(void *context, struct rpc_request *req);
+static rpc_status_t verify_pkcs7_signature_handler(void *context, struct rpc_request *req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
- {TS_CRYPTO_OPCODE_GENERATE_KEY, generate_key_handler},
- {TS_CRYPTO_OPCODE_DESTROY_KEY, destroy_key_handler},
- {TS_CRYPTO_OPCODE_EXPORT_KEY, export_key_handler},
- {TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, export_public_key_handler},
- {TS_CRYPTO_OPCODE_IMPORT_KEY, import_key_handler},
- {TS_CRYPTO_OPCODE_SIGN_HASH, sign_hash_handler},
- {TS_CRYPTO_OPCODE_VERIFY_HASH, verify_hash_handler},
- {TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, asymmetric_decrypt_handler},
- {TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, asymmetric_encrypt_handler},
- {TS_CRYPTO_OPCODE_GENERATE_RANDOM, generate_random_handler},
- {TS_CRYPTO_OPCODE_COPY_KEY, copy_key_handler},
- {TS_CRYPTO_OPCODE_PURGE_KEY, purge_key_handler},
- {TS_CRYPTO_OPCODE_GET_KEY_ATTRIBUTES, get_key_attributes_handler},
+ { TS_CRYPTO_OPCODE_GENERATE_KEY, generate_key_handler },
+ { TS_CRYPTO_OPCODE_DESTROY_KEY, destroy_key_handler },
+ { TS_CRYPTO_OPCODE_EXPORT_KEY, export_key_handler },
+ { TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, export_public_key_handler },
+ { TS_CRYPTO_OPCODE_IMPORT_KEY, import_key_handler },
+ { TS_CRYPTO_OPCODE_SIGN_HASH, asymmetric_sign_handler },
+ { TS_CRYPTO_OPCODE_VERIFY_HASH, asymmetric_verify_handler },
+ { TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, asymmetric_decrypt_handler },
+ { TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, asymmetric_encrypt_handler },
+ { TS_CRYPTO_OPCODE_GENERATE_RANDOM, generate_random_handler },
+ { TS_CRYPTO_OPCODE_COPY_KEY, copy_key_handler },
+ { TS_CRYPTO_OPCODE_PURGE_KEY, purge_key_handler },
+ { TS_CRYPTO_OPCODE_GET_KEY_ATTRIBUTES, get_key_attributes_handler },
+ { TS_CRYPTO_OPCODE_SIGN_MESSAGE, asymmetric_sign_handler },
+ { TS_CRYPTO_OPCODE_VERIFY_MESSAGE, asymmetric_verify_handler },
+ { TS_CRYPTO_OPCODE_VERIFY_PKCS7_SIGNATURE, verify_pkcs7_signature_handler },
};
-struct rpc_interface *crypto_provider_init(struct crypto_provider *context)
+struct rpc_service_interface *
+crypto_provider_init(struct crypto_provider *context, unsigned int encoding,
+ const struct crypto_provider_serializer *serializer)
{
- /* Initialise the crypto provider */
- for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
- context->serializers[encoding] = NULL;
+ const struct rpc_uuid crypto_service_uuid[2] = {
+ { .uuid = TS_PSA_CRYPTO_SERVICE_UUID },
+ { .uuid = TS_PSA_CRYPTO_PROTOBUF_SERVICE_UUID },
+ };
+
+ if (encoding >= TS_RPC_ENCODING_LIMIT)
+ return NULL;
- service_provider_init(&context->base_provider, context,
- handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+ context->serializer = serializer;
- /* Initialise the associated discovery provider */
- discovery_provider_init(&context->discovery_provider);
- service_provider_extend(&context->base_provider, &context->discovery_provider.base_provider);
+ service_provider_init(&context->base_provider, context, &crypto_service_uuid[encoding],
+ handler_table,
+ sizeof(handler_table) / sizeof(struct service_handler));
return service_provider_get_rpc_interface(&context->base_provider);
}
void crypto_provider_deinit(struct crypto_provider *context)
{
- discovery_provider_deinit(&context->discovery_provider);
+ (void)context;
}
void crypto_provider_register_serializer(struct crypto_provider *context,
- unsigned int encoding, const struct crypto_provider_serializer *serializer)
+ const struct crypto_provider_serializer *serializer)
{
- if (encoding < TS_RPC_ENCODING_LIMIT) {
-
- context->serializers[encoding] = serializer;
- discovery_provider_register_supported_encoding(&context->discovery_provider, encoding);
- }
+ context->serializer = serializer;
}
-void crypto_provider_extend(struct crypto_provider *context,
- struct service_provider *sub_provider)
+void crypto_provider_extend(struct crypto_provider *context, struct service_provider *sub_provider)
{
service_provider_extend(&context->base_provider, sub_provider);
}
-static const struct crypto_provider_serializer* get_crypto_serializer(void *context,
- const struct call_req *req)
+static const struct crypto_provider_serializer *get_crypto_serializer(void *context,
+ const struct rpc_request *req)
{
- struct crypto_provider *this_instance = (struct crypto_provider*)context;
- const struct crypto_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
-
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+ struct crypto_provider *this_instance = (struct crypto_provider *)context;
- return serializer;
+ return this_instance->serializer;
}
-static rpc_status_t generate_key_handler(void *context, struct call_req* req)
+static rpc_status_t generate_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
@@ -102,20 +107,18 @@ static rpc_status_t generate_key_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_generate_key_req(req_buf, &attributes);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status;
psa_key_id_t id;
psa_status = psa_generate_key(&attributes, &id);
if (psa_status == PSA_SUCCESS) {
-
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_generate_key_resp(resp_buf, id);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
psa_reset_key_attributes(&attributes);
@@ -123,10 +126,10 @@ static rpc_status_t generate_key_handler(void *context, struct call_req* req)
return rpc_status;
}
-static rpc_status_t destroy_key_handler(void *context, struct call_req* req)
+static rpc_status_t destroy_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_id_t id;
@@ -134,21 +137,20 @@ static rpc_status_t destroy_key_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_destroy_key_req(req_buf, &id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status;
psa_status = psa_destroy_key(id);
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t export_key_handler(void *context, struct call_req* req)
+static rpc_status_t export_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_id_t id;
@@ -156,40 +158,37 @@ static rpc_status_t export_key_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_export_key_req(req_buf, &id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
size_t max_export_size = PSA_EXPORT_KEY_PAIR_MAX_SIZE;
uint8_t *key_buffer = malloc(max_export_size);
if (key_buffer) {
-
size_t export_size;
- psa_status_t psa_status = psa_export_key(id, key_buffer,
- max_export_size, &export_size);
+ psa_status_t psa_status =
+ psa_export_key(id, key_buffer, max_export_size, &export_size);
if (psa_status == PSA_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_export_key_resp(resp_buf,
- key_buffer, export_size);
+ rpc_status = serializer->serialize_export_key_resp(
+ resp_buf, key_buffer, export_size);
}
free(key_buffer);
- call_req_set_opstatus(req, psa_status);
- }
- else {
+ req->service_status = psa_status;
+ } else {
/* Failed to allocate key buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t export_public_key_handler(void *context, struct call_req* req)
+static rpc_status_t export_public_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_id_t id;
@@ -197,85 +196,79 @@ static rpc_status_t export_public_key_handler(void *context, struct call_req* re
if (serializer)
rpc_status = serializer->deserialize_export_public_key_req(req_buf, &id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
size_t max_export_size = PSA_EXPORT_PUBLIC_KEY_MAX_SIZE;
uint8_t *key_buffer = malloc(max_export_size);
if (key_buffer) {
-
size_t export_size;
- psa_status_t psa_status = psa_export_public_key(id, key_buffer,
- max_export_size, &export_size);
+ psa_status_t psa_status = psa_export_public_key(
+ id, key_buffer, max_export_size, &export_size);
if (psa_status == PSA_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_export_public_key_resp(resp_buf,
- key_buffer, export_size);
+ rpc_status = serializer->serialize_export_public_key_resp(
+ resp_buf, key_buffer, export_size);
}
free(key_buffer);
- call_req_set_opstatus(req, psa_status);
- }
- else {
+ req->service_status = psa_status;
+ } else {
/* Failed to allocate key buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t import_key_handler(void *context, struct call_req* req)
+static rpc_status_t import_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
if (serializer) {
-
size_t key_data_len = serializer->max_deserialised_parameter_size(req_buf);
uint8_t *key_buffer = malloc(key_data_len);
if (key_buffer) {
-
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- rpc_status = serializer->deserialize_import_key_req(req_buf, &attributes,
- key_buffer, &key_data_len);
-
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ rpc_status = serializer->deserialize_import_key_req(
+ req_buf, &attributes, key_buffer, &key_data_len);
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status;
psa_key_id_t id;
- psa_status = psa_import_key(&attributes, key_buffer, key_data_len, &id);
+ psa_status =
+ psa_import_key(&attributes, key_buffer, key_data_len, &id);
if (psa_status == PSA_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_import_key_resp(resp_buf, id);
+ rpc_status =
+ serializer->serialize_import_key_resp(resp_buf, id);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
psa_reset_key_attributes(&attributes);
free(key_buffer);
- }
- else {
-
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ } else {
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t sign_hash_handler(void *context, struct call_req* req)
+static rpc_status_t asymmetric_sign_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_id_t id;
@@ -284,34 +277,37 @@ static rpc_status_t sign_hash_handler(void *context, struct call_req* req)
uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
if (serializer)
- rpc_status = serializer->deserialize_sign_hash_req(req_buf, &id, &alg, hash_buffer, &hash_len);
-
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ rpc_status = serializer->deserialize_asymmetric_sign_req(req_buf, &id, &alg,
+ hash_buffer, &hash_len);
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status;
size_t sig_len;
uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
- psa_status = psa_sign_hash(id, alg,
- hash_buffer, hash_len,
- sig_buffer, sizeof(sig_buffer), &sig_len);
+ psa_status = (req->opcode == TS_CRYPTO_OPCODE_SIGN_HASH) ?
+ psa_sign_hash(id, alg, hash_buffer, hash_len, sig_buffer,
+ sizeof(sig_buffer), &sig_len) :
+ psa_sign_message(id, alg, hash_buffer, hash_len, sig_buffer,
+ sizeof(sig_buffer), &sig_len);
if (psa_status == PSA_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_sign_hash_resp(resp_buf, sig_buffer, sig_len);
+ rpc_status = serializer->serialize_asymmetric_sign_resp(
+ resp_buf, sig_buffer, sig_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t verify_hash_handler(void *context, struct call_req* req)
+static rpc_status_t asymmetric_verify_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_id_t id;
@@ -322,32 +318,31 @@ static rpc_status_t verify_hash_handler(void *context, struct call_req* req)
uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
if (serializer)
- rpc_status = serializer->deserialize_verify_hash_req(req_buf, &id, &alg,
- hash_buffer, &hash_len,
- sig_buffer, &sig_len);
-
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ rpc_status = serializer->deserialize_asymmetric_verify_req(
+ req_buf, &id, &alg, hash_buffer, &hash_len, sig_buffer, &sig_len);
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status;
- psa_status = psa_verify_hash(id, alg,
- hash_buffer, hash_len,
- sig_buffer, sig_len);
+ psa_status = (req->opcode == TS_CRYPTO_OPCODE_VERIFY_HASH) ?
+ psa_verify_hash(id, alg, hash_buffer, hash_len, sig_buffer,
+ sig_len) :
+ psa_verify_message(id, alg, hash_buffer, hash_len, sig_buffer,
+ sig_len);
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t asymmetric_decrypt_handler(void *context, struct call_req* req)
+static rpc_status_t asymmetric_decrypt_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
if (serializer) {
-
size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
psa_key_id_t id;
@@ -358,61 +353,54 @@ static rpc_status_t asymmetric_decrypt_handler(void *context, struct call_req* r
uint8_t *salt_buffer = malloc(salt_len);
if (ciphertext_buffer && salt_buffer) {
+ rpc_status = serializer->deserialize_asymmetric_decrypt_req(
+ req_buf, &id, &alg, ciphertext_buffer, &ciphertext_len, salt_buffer,
+ &salt_len);
- rpc_status = serializer->deserialize_asymmetric_decrypt_req(req_buf,
- &id, &alg,
- ciphertext_buffer, &ciphertext_len,
- salt_buffer, &salt_len);
-
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_status = psa_get_key_attributes(id, &attributes);
if (psa_status == PSA_SUCCESS) {
-
- size_t max_decrypt_size = PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(
- psa_get_key_type(&attributes),
- psa_get_key_bits(&attributes),
- alg);
+ size_t max_decrypt_size =
+ PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(
+ psa_get_key_type(&attributes),
+ psa_get_key_bits(&attributes), alg);
size_t plaintext_len;
uint8_t *plaintext_buffer = malloc(max_decrypt_size);
if (plaintext_buffer) {
-
/* Salt is an optional parameter */
uint8_t *salt = (salt_len) ? salt_buffer : NULL;
- psa_status = psa_asymmetric_decrypt(id, alg,
- ciphertext_buffer, ciphertext_len,
- salt, salt_len,
- plaintext_buffer, max_decrypt_size, &plaintext_len);
+ psa_status = psa_asymmetric_decrypt(
+ id, alg, ciphertext_buffer, ciphertext_len,
+ salt, salt_len, plaintext_buffer,
+ max_decrypt_size, &plaintext_len);
if (psa_status == PSA_SUCCESS) {
-
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_asymmetric_decrypt_resp(resp_buf,
- plaintext_buffer, plaintext_len);
+ struct rpc_buffer *resp_buf =
+ &req->response;
+ rpc_status = serializer->serialize_asymmetric_decrypt_resp(
+ resp_buf, plaintext_buffer, plaintext_len);
}
free(plaintext_buffer);
- }
- else {
+ } else {
/* Failed to allocate ouptput buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
psa_reset_key_attributes(&attributes);
}
- }
- else {
+ } else {
/* Failed to allocate buffers */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
free(ciphertext_buffer);
@@ -422,14 +410,13 @@ static rpc_status_t asymmetric_decrypt_handler(void *context, struct call_req* r
return rpc_status;
}
-static rpc_status_t asymmetric_encrypt_handler(void *context, struct call_req* req)
+static rpc_status_t asymmetric_encrypt_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
if (serializer) {
-
size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
psa_key_id_t id;
@@ -440,61 +427,55 @@ static rpc_status_t asymmetric_encrypt_handler(void *context, struct call_req* r
uint8_t *salt_buffer = malloc(salt_len);
if (plaintext_buffer && salt_buffer) {
+ rpc_status = serializer->deserialize_asymmetric_encrypt_req(
+ req_buf, &id, &alg, plaintext_buffer, &plaintext_len, salt_buffer,
+ &salt_len);
- rpc_status = serializer->deserialize_asymmetric_encrypt_req(req_buf,
- &id, &alg,
- plaintext_buffer, &plaintext_len,
- salt_buffer, &salt_len);
-
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_status = psa_get_key_attributes(id, &attributes);
if (psa_status == PSA_SUCCESS) {
-
- size_t max_encrypt_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(
- psa_get_key_type(&attributes),
- psa_get_key_bits(&attributes),
- alg);
+ size_t max_encrypt_size =
+ PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(
+ psa_get_key_type(&attributes),
+ psa_get_key_bits(&attributes), alg);
size_t ciphertext_len;
uint8_t *ciphertext_buffer = malloc(max_encrypt_size);
if (ciphertext_buffer) {
-
/* Salt is an optional parameter */
uint8_t *salt = (salt_len) ? salt_buffer : NULL;
- psa_status = psa_asymmetric_encrypt(id, alg,
- plaintext_buffer, plaintext_len,
- salt, salt_len,
- ciphertext_buffer, max_encrypt_size, &ciphertext_len);
+ psa_status = psa_asymmetric_encrypt(
+ id, alg, plaintext_buffer, plaintext_len,
+ salt, salt_len, ciphertext_buffer,
+ max_encrypt_size, &ciphertext_len);
if (psa_status == PSA_SUCCESS) {
+ struct rpc_buffer *resp_buf =
+ &req->response;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_asymmetric_encrypt_resp(resp_buf,
- ciphertext_buffer, ciphertext_len);
+ rpc_status = serializer->serialize_asymmetric_encrypt_resp(
+ resp_buf, ciphertext_buffer, ciphertext_len);
}
free(ciphertext_buffer);
- }
- else {
+ } else {
/* Failed to allocate ouptput buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
psa_reset_key_attributes(&attributes);
}
- }
- else {
+ } else {
/* Failed to allocate buffers */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
free(plaintext_buffer);
@@ -504,10 +485,10 @@ static rpc_status_t asymmetric_encrypt_handler(void *context, struct call_req* r
return rpc_status;
}
-static rpc_status_t generate_random_handler(void *context, struct call_req* req)
+static rpc_status_t generate_random_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
size_t output_size;
@@ -515,59 +496,55 @@ static rpc_status_t generate_random_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_generate_random_req(req_buf, &output_size);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status;
uint8_t *output_buffer = malloc(output_size);
if (output_buffer) {
-
psa_status = psa_generate_random(output_buffer, output_size);
if (psa_status == PSA_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_generate_random_resp(resp_buf,
- output_buffer, output_size);
+ rpc_status = serializer->serialize_generate_random_resp(
+ resp_buf, output_buffer, output_size);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
free(output_buffer);
- }
- else {
+ } else {
/* Failed to allocate output buffer */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t copy_key_handler(void *context, struct call_req* req)
+static rpc_status_t copy_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t source_key_id;
if (serializer)
- rpc_status = serializer->deserialize_copy_key_req(req_buf, &attributes, &source_key_id);
-
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ rpc_status =
+ serializer->deserialize_copy_key_req(req_buf, &attributes, &source_key_id);
+ if (rpc_status == RPC_SUCCESS) {
psa_key_id_t target_key_id;
psa_status_t psa_status = psa_copy_key(source_key_id, &attributes, &target_key_id);
if (psa_status == PSA_SUCCESS) {
-
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_copy_key_resp(resp_buf, target_key_id);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
psa_reset_key_attributes(&attributes);
@@ -575,10 +552,10 @@ static rpc_status_t copy_key_handler(void *context, struct call_req* req)
return rpc_status;
}
-static rpc_status_t purge_key_handler(void *context, struct call_req* req)
+static rpc_status_t purge_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_id_t id;
@@ -586,19 +563,18 @@ static rpc_status_t purge_key_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_purge_key_req(req_buf, &id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = psa_purge_key(id);
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t get_key_attributes_handler(void *context, struct call_req* req)
+static rpc_status_t get_key_attributes_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
psa_key_id_t id;
@@ -606,21 +582,98 @@ static rpc_status_t get_key_attributes_handler(void *context, struct call_req* r
if (serializer)
rpc_status = serializer->deserialize_get_key_attributes_req(req_buf, &id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
-
+ if (rpc_status == RPC_SUCCESS) {
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_status_t psa_status = psa_get_key_attributes(id, &attributes);
if (psa_status == PSA_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_get_key_attributes_resp(resp_buf, &attributes);
+ rpc_status = serializer->serialize_get_key_attributes_resp(resp_buf,
+ &attributes);
}
psa_reset_key_attributes(&attributes);
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
+
+static rpc_status_t verify_pkcs7_signature_handler(void *context, struct rpc_request *req)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
+ const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+
+ int mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+
+ uint8_t *signature_cert = NULL;
+ uint64_t signature_cert_len = 0;
+ uint8_t *hash = NULL;
+ uint64_t hash_len = 0;
+ uint8_t *public_key_cert = NULL;
+ uint64_t public_key_cert_len = 0;
+
+ if (serializer) {
+ /* First collect the lengths of the fields */
+ rpc_status = serializer->deserialize_verify_pkcs7_signature_req(
+ req_buf, NULL, &signature_cert_len, NULL, &hash_len, NULL,
+ &public_key_cert_len);
+
+ if (rpc_status == RPC_SUCCESS) {
+ /* Allocate the needed space and get the data */
+ signature_cert = (uint8_t *)malloc(signature_cert_len);
+ hash = (uint8_t *)malloc(hash_len);
+ public_key_cert = (uint8_t *)malloc(public_key_cert_len);
+
+ if (signature_cert && hash && public_key_cert) {
+ rpc_status = serializer->deserialize_verify_pkcs7_signature_req(
+ req_buf, signature_cert, &signature_cert_len, hash,
+ &hash_len, public_key_cert, &public_key_cert_len);
+ } else {
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
+ }
+
+ if (rpc_status == RPC_SUCCESS) {
+ /* Parse the public key certificate */
+ mbedtls_x509_crt signer_certificate;
+
+ mbedtls_x509_crt_init(&signer_certificate);
+
+ mbedtls_status = mbedtls_x509_crt_parse_der(&signer_certificate, public_key_cert,
+ public_key_cert_len);
+
+ if (mbedtls_status == 0) {
+ /* Parse the PKCS#7 DER encoded signature block */
+ mbedtls_pkcs7 pkcs7_structure;
+
+ mbedtls_pkcs7_init(&pkcs7_structure);
+
+ mbedtls_status = mbedtls_pkcs7_parse_der(&pkcs7_structure, signature_cert,
+ signature_cert_len);
+
+ if (mbedtls_status == MBEDTLS_PKCS7_SIGNED_DATA) {
+ /* Verify hash against signed hash */
+ mbedtls_status = mbedtls_pkcs7_signed_hash_verify(
+ &pkcs7_structure, &signer_certificate, hash, hash_len);
+ }
+
+ mbedtls_pkcs7_free(&pkcs7_structure);
+ }
+
+ mbedtls_x509_crt_free(&signer_certificate);
+ }
+
+ free(signature_cert);
+ free(hash);
+ free(public_key_cert);
+
+ /* Provide the result of the verification */
+ req->service_status = mbedtls_status;
+
+ return rpc_status;
+}
diff --git a/components/service/crypto/provider/crypto_provider.h b/components/service/crypto/provider/crypto_provider.h
index ce33c23b8..17202646c 100644
--- a/components/service/crypto/provider/crypto_provider.h
+++ b/components/service/crypto/provider/crypto_provider.h
@@ -7,10 +7,9 @@
#ifndef CRYPTO_PROVIDER_H
#define CRYPTO_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include <service/common/provider/service_provider.h>
#include <service/crypto/provider/serializer/crypto_provider_serializer.h>
-#include <service/discovery/provider/discovery_provider.h>
#include <protocols/rpc/common/packed-c/encoding.h>
#ifdef __cplusplus
@@ -20,8 +19,7 @@ extern "C" {
struct crypto_provider
{
struct service_provider base_provider;
- const struct crypto_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
- struct discovery_provider discovery_provider;
+ const struct crypto_provider_serializer *serializer;
};
/*
@@ -29,7 +27,8 @@ struct crypto_provider
* backend that realizes the PSA Crypto API should have been initialized
* prior to initializing the crypto provider.
*/
-struct rpc_interface *crypto_provider_init(struct crypto_provider *context);
+struct rpc_service_interface *crypto_provider_init(struct crypto_provider *context,
+ unsigned int encoding, const struct crypto_provider_serializer *serializer);
/*
* When operation of the provider is no longer required, this function
@@ -44,7 +43,6 @@ void crypto_provider_deinit(struct crypto_provider *context);
* for compatibility with different types of client.
*/
void crypto_provider_register_serializer(struct crypto_provider *context,
- unsigned int encoding,
const struct crypto_provider_serializer *serializer);
/*
diff --git a/components/service/crypto/provider/crypto_uuid.h b/components/service/crypto/provider/crypto_uuid.h
new file mode 100644
index 000000000..ec35f2444
--- /dev/null
+++ b/components/service/crypto/provider/crypto_uuid.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_UUID_H
+#define CRYPTO_UUID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TS_PSA_CRYPTO_SERVICE_UUID \
+{ 0xd9, 0xdf, 0x52, 0xd5, 0x16, 0xa2, 0x4b, 0xb2, 0x9a, 0xa4, 0xd2, 0x6d, 0x3b, 0x84, 0xe8, 0xc0 }
+
+#define TS_PSA_CRYPTO_PROTOBUF_SERVICE_UUID \
+{ 0x6b, 0xa9, 0xde, 0x75, 0x39, 0x3e, 0x4c, 0x7f, 0xaa, 0xbb, 0x7f, 0x71, 0xcc, 0x6b, 0x14, 0x2e }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CRYPTO_UUID_H */
diff --git a/components/service/crypto/provider/extension/aead/aead_provider.c b/components/service/crypto/provider/extension/aead/aead_provider.c
index f4e81a036..696474e8d 100644
--- a/components/service/crypto/provider/extension/aead/aead_provider.c
+++ b/components/service/crypto/provider/extension/aead/aead_provider.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,15 +11,15 @@
#include <psa/crypto.h>
/* Service request handlers */
-static rpc_status_t aead_setup_handler(void *context, struct call_req *req);
-static rpc_status_t aead_generate_nonce_handler(void *context, struct call_req *req);
-static rpc_status_t aead_set_nonce_handler(void *context, struct call_req *req);
-static rpc_status_t aead_set_lengths_handler(void *context, struct call_req *req);
-static rpc_status_t aead_update_ad_handler(void *context, struct call_req *req);
-static rpc_status_t aead_update_handler(void *context, struct call_req *req);
-static rpc_status_t aead_finish_handler(void *context, struct call_req *req);
-static rpc_status_t aead_verify_handler(void *context, struct call_req *req);
-static rpc_status_t aead_abort_handler(void *context, struct call_req *req);
+static rpc_status_t aead_setup_handler(void *context, struct rpc_request *req);
+static rpc_status_t aead_generate_nonce_handler(void *context, struct rpc_request *req);
+static rpc_status_t aead_set_nonce_handler(void *context, struct rpc_request *req);
+static rpc_status_t aead_set_lengths_handler(void *context, struct rpc_request *req);
+static rpc_status_t aead_update_ad_handler(void *context, struct rpc_request *req);
+static rpc_status_t aead_update_handler(void *context, struct rpc_request *req);
+static rpc_status_t aead_finish_handler(void *context, struct rpc_request *req);
+static rpc_status_t aead_verify_handler(void *context, struct rpc_request *req);
+static rpc_status_t aead_abort_handler(void *context, struct rpc_request *req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
@@ -37,12 +37,14 @@ static const struct service_handler handler_table[] = {
void aead_provider_init(struct aead_provider *context)
{
+ const struct rpc_uuid nil_uuid = { 0 };
+
crypto_context_pool_init(&context->context_pool);
for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
context->serializers[encoding] = NULL;
- service_provider_init(&context->base_provider, context,
+ service_provider_init(&context->base_provider, context, &nil_uuid,
handler_table, sizeof(handler_table)/sizeof(struct service_handler));
}
@@ -59,21 +61,18 @@ void aead_provider_register_serializer(struct aead_provider *context,
}
static const struct aead_provider_serializer* get_serializer(void *context,
- const struct call_req *req)
+ const struct rpc_request *req)
{
struct aead_provider *this_instance = (struct aead_provider*)context;
- const struct aead_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
-
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+ unsigned int encoding = 0; /* No other encodings supported */
- return serializer;
+ return this_instance->serializers[encoding];
}
-static rpc_status_t aead_setup_handler(void *context, struct call_req *req)
+static rpc_status_t aead_setup_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -83,13 +82,13 @@ static rpc_status_t aead_setup_handler(void *context, struct call_req *req)
if (serializer)
rpc_status = serializer->deserialize_aead_setup_req(req_buf, &key_id, &alg);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
uint32_t op_handle;
struct crypto_context *crypto_context =
crypto_context_pool_alloc(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
&op_handle);
if (crypto_context) {
@@ -98,36 +97,34 @@ static rpc_status_t aead_setup_handler(void *context, struct call_req *req)
crypto_context->op.aead = psa_aead_operation_init();
- psa_status = (call_req_get_opcode(req) == TS_CRYPTO_OPCODE_AEAD_ENCRYPT_SETUP) ?
+ psa_status = (req->opcode == TS_CRYPTO_OPCODE_AEAD_ENCRYPT_SETUP) ?
psa_aead_encrypt_setup(&crypto_context->op.aead, key_id, alg) :
psa_aead_decrypt_setup(&crypto_context->op.aead, key_id, alg);
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_aead_setup_resp(resp_buf, op_handle);
}
- if ((psa_status != PSA_SUCCESS) || (rpc_status != TS_RPC_CALL_ACCEPTED)) {
-
+ if ((psa_status != PSA_SUCCESS) || (rpc_status != RPC_SUCCESS))
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
- }
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
else {
/* Failed to allocate crypto context for transaction */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t aead_generate_nonce_handler(void *context, struct call_req *req)
+static rpc_status_t aead_generate_nonce_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -136,13 +133,13 @@ static rpc_status_t aead_generate_nonce_handler(void *context, struct call_req *
if (serializer)
rpc_status = serializer->deserialize_aead_generate_nonce_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
op_handle);
if (crypto_context) {
@@ -155,22 +152,22 @@ static rpc_status_t aead_generate_nonce_handler(void *context, struct call_req *
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_aead_generate_nonce_resp(resp_buf,
nonce, nonce_len);
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t aead_set_nonce_handler(void *context, struct call_req *req)
+static rpc_status_t aead_set_nonce_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -182,13 +179,13 @@ static rpc_status_t aead_set_nonce_handler(void *context, struct call_req *req)
rpc_status = serializer->deserialize_aead_set_nonce_req(req_buf, &op_handle,
&nonce, &nonce_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
op_handle);
if (crypto_context) {
@@ -196,16 +193,16 @@ static rpc_status_t aead_set_nonce_handler(void *context, struct call_req *req)
psa_status = psa_aead_set_nonce(&crypto_context->op.aead, nonce, nonce_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t aead_set_lengths_handler(void *context, struct call_req *req)
+static rpc_status_t aead_set_lengths_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -217,13 +214,13 @@ static rpc_status_t aead_set_lengths_handler(void *context, struct call_req *req
rpc_status = serializer->deserialize_aead_set_lengths_req(req_buf, &op_handle,
&ad_length, &plaintext_length);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
op_handle);
if (crypto_context) {
@@ -232,16 +229,16 @@ static rpc_status_t aead_set_lengths_handler(void *context, struct call_req *req
ad_length, plaintext_length);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t aead_update_ad_handler(void *context, struct call_req *req)
+static rpc_status_t aead_update_ad_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -253,13 +250,13 @@ static rpc_status_t aead_update_ad_handler(void *context, struct call_req *req)
rpc_status = serializer->deserialize_aead_update_ad_req(req_buf, &op_handle,
&input, &input_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
op_handle);
if (crypto_context) {
@@ -267,16 +264,16 @@ static rpc_status_t aead_update_ad_handler(void *context, struct call_req *req)
psa_status = psa_aead_update_ad(&crypto_context->op.aead, input, input_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t aead_update_handler(void *context, struct call_req *req)
+static rpc_status_t aead_update_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -288,13 +285,13 @@ static rpc_status_t aead_update_handler(void *context, struct call_req *req)
rpc_status = serializer->deserialize_aead_update_req(req_buf, &op_handle,
&input, &input_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
op_handle);
if (crypto_context) {
@@ -311,7 +308,7 @@ static rpc_status_t aead_update_handler(void *context, struct call_req *req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_aead_update_resp(resp_buf,
output, output_len);
}
@@ -324,16 +321,16 @@ static rpc_status_t aead_update_handler(void *context, struct call_req *req)
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t aead_finish_handler(void *context, struct call_req *req)
+static rpc_status_t aead_finish_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -342,13 +339,13 @@ static rpc_status_t aead_finish_handler(void *context, struct call_req *req)
if (serializer)
rpc_status = serializer->deserialize_aead_finish_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
op_handle);
if (crypto_context) {
@@ -365,25 +362,25 @@ static rpc_status_t aead_finish_handler(void *context, struct call_req *req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_aead_finish_resp(resp_buf,
ciphertext, ciphertext_len,
tag, tag_len);
- }
- crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ }
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t aead_verify_handler(void *context, struct call_req *req)
+static rpc_status_t aead_verify_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -395,13 +392,13 @@ static rpc_status_t aead_verify_handler(void *context, struct call_req *req)
rpc_status = serializer->deserialize_aead_verify_req(req_buf, &op_handle,
&tag, &tag_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
op_handle);
if (crypto_context) {
@@ -415,24 +412,24 @@ static rpc_status_t aead_verify_handler(void *context, struct call_req *req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_aead_verify_resp(resp_buf,
plaintext, plaintext_len);
- }
- crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ }
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t aead_abort_handler(void *context, struct call_req *req)
+static rpc_status_t aead_abort_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct aead_provider_serializer *serializer = get_serializer(context, req);
struct aead_provider *this_instance = (struct aead_provider*)context;
@@ -441,7 +438,7 @@ static rpc_status_t aead_abort_handler(void *context, struct call_req *req)
if (serializer)
rpc_status = serializer->deserialize_aead_abort_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
/* Return success if operation is no longer active and
* doesn't need aborting.
@@ -450,7 +447,7 @@ static rpc_status_t aead_abort_handler(void *context, struct call_req *req)
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_AEAD, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_AEAD, req->source_id,
op_handle);
if (crypto_context) {
@@ -459,7 +456,7 @@ static rpc_status_t aead_abort_handler(void *context, struct call_req *req)
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/aead/aead_provider.h b/components/service/crypto/provider/extension/aead/aead_provider.h
index 33fa7d0bc..b25cde870 100644
--- a/components/service/crypto/provider/extension/aead/aead_provider.h
+++ b/components/service/crypto/provider/extension/aead/aead_provider.h
@@ -7,7 +7,7 @@
#ifndef AEAD_PROVIDER_H
#define AEAD_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include <service/common/provider/service_provider.h>
#include <service/crypto/provider/extension/aead/serializer/aead_provider_serializer.h>
#include <service/crypto/provider/crypto_context_pool.h>
diff --git a/components/service/crypto/provider/extension/aead/serializer/aead_provider_serializer.h b/components/service/crypto/provider/extension/aead/serializer/aead_provider_serializer.h
index bb1a2a97e..2bf7a0159 100644
--- a/components/service/crypto/provider/extension/aead/serializer/aead_provider_serializer.h
+++ b/components/service/crypto/provider/extension/aead/serializer/aead_provider_serializer.h
@@ -10,7 +10,7 @@
#include <stddef.h>
#include <stdint.h>
#include <psa/crypto.h>
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
/* Provides a common interface for parameter serialization operations
* for the aead service provider.
@@ -18,62 +18,62 @@
struct aead_provider_serializer {
/* Operation: aead_setup */
- rpc_status_t (*deserialize_aead_setup_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_setup_req)(const struct rpc_buffer *req_buf,
psa_key_id_t *id,
psa_algorithm_t *alg);
- rpc_status_t (*serialize_aead_setup_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_aead_setup_resp)(struct rpc_buffer *resp_buf,
uint32_t op_handle);
/* Operation: aead_generate_nonce */
- rpc_status_t (*deserialize_aead_generate_nonce_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_generate_nonce_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
- rpc_status_t (*serialize_aead_generate_nonce_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_aead_generate_nonce_resp)(struct rpc_buffer *resp_buf,
const uint8_t *nonce, size_t nonce_len);
/* Operation: aead_set_nonce */
- rpc_status_t (*deserialize_aead_set_nonce_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_set_nonce_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **nonce, size_t *nonce_len);
/* Operation: aead_set_lengths */
- rpc_status_t (*deserialize_aead_set_lengths_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_set_lengths_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
size_t *ad_length,
size_t *plaintext_length);
/* Operation: aead_update_ad */
- rpc_status_t (*deserialize_aead_update_ad_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_update_ad_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **input, size_t *input_len);
/* Operation: aead_update */
- rpc_status_t (*deserialize_aead_update_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_update_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **input, size_t *input_len);
- rpc_status_t (*serialize_aead_update_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_aead_update_resp)(struct rpc_buffer *resp_buf,
const uint8_t *output, size_t output_len);
/* Operation: aead_finish */
- rpc_status_t (*deserialize_aead_finish_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_finish_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
- rpc_status_t (*serialize_aead_finish_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_aead_finish_resp)(struct rpc_buffer *resp_buf,
const uint8_t *aeadtext, size_t aeadtext_len,
const uint8_t *tag, size_t tag_len);
/* Operation: aead_verify */
- rpc_status_t (*deserialize_aead_verify_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_verify_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **tag, size_t *tag_len);
- rpc_status_t (*serialize_aead_verify_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_aead_verify_resp)(struct rpc_buffer *resp_buf,
const uint8_t *plaintext, size_t plaintext_len);
/* Operation: aead_abort */
- rpc_status_t (*deserialize_aead_abort_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_aead_abort_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
};
diff --git a/components/service/crypto/provider/extension/aead/serializer/packed-c/packedc_aead_provider_serializer.c b/components/service/crypto/provider/extension/aead/serializer/packed-c/packedc_aead_provider_serializer.c
index 6f00b3e3f..738d5f23b 100644
--- a/components/service/crypto/provider/extension/aead/serializer/packed-c/packedc_aead_provider_serializer.c
+++ b/components/service/crypto/provider/extension/aead/serializer/packed-c/packedc_aead_provider_serializer.c
@@ -11,29 +11,29 @@
#include "packedc_aead_provider_serializer.h"
/* Operation: aead_setup */
-static rpc_status_t deserialize_aead_setup_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_setup_req(const struct rpc_buffer *req_buf,
psa_key_id_t *id,
psa_algorithm_t *alg)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_setup_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_setup_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*id = recv_msg.key_id;
*alg = recv_msg.alg;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_aead_setup_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_aead_setup_resp(struct rpc_buffer *resp_buf,
uint32_t op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct ts_crypto_aead_setup_out resp_msg;
size_t fixed_len = sizeof(struct ts_crypto_aead_setup_out);
@@ -42,35 +42,35 @@ static rpc_status_t serialize_aead_setup_resp(struct call_param_buf *resp_buf,
if (fixed_len <= resp_buf->size) {
memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: aead_generate_nonce */
-static rpc_status_t deserialize_aead_generate_nonce_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_generate_nonce_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_generate_nonce_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_generate_nonce_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_aead_generate_nonce_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_aead_generate_nonce_resp(struct rpc_buffer *resp_buf,
const uint8_t *nonce, size_t nonce_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
@@ -82,28 +82,28 @@ static rpc_status_t serialize_aead_generate_nonce_resp(struct call_param_buf *re
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(out_record.length);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(out_record.length);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: aead_set_nonce */
-static rpc_status_t deserialize_aead_set_nonce_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_set_nonce_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **nonce, size_t *nonce_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_set_nonce_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_set_nonce_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -111,7 +111,7 @@ static rpc_status_t deserialize_aead_set_nonce_req(const struct call_param_buf *
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_AEAD_SET_NONCE_IN_TAG_NONCE, &decoded_record)) {
@@ -128,18 +128,18 @@ static rpc_status_t deserialize_aead_set_nonce_req(const struct call_param_buf *
}
/* Operation: aead_set_lengths */
-static rpc_status_t deserialize_aead_set_lengths_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_set_lengths_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
size_t *ad_length,
size_t *plaintext_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_set_lengths_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_set_lengths_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -152,20 +152,20 @@ static rpc_status_t deserialize_aead_set_lengths_req(const struct call_param_buf
}
/* Operation: aead_update_ad */
-static rpc_status_t deserialize_aead_update_ad_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_update_ad_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **input, size_t *input_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_update_ad_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_update_ad_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -173,7 +173,7 @@ static rpc_status_t deserialize_aead_update_ad_req(const struct call_param_buf *
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_AEAD_UPDATE_AD_IN_TAG_DATA, &decoded_record)) {
@@ -190,20 +190,20 @@ static rpc_status_t deserialize_aead_update_ad_req(const struct call_param_buf *
}
/* Operation: aead_update */
-static rpc_status_t deserialize_aead_update_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_update_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **input, size_t *input_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_update_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_update_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -211,7 +211,7 @@ static rpc_status_t deserialize_aead_update_req(const struct call_param_buf *req
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_AEAD_UPDATE_IN_TAG_DATA, &decoded_record)) {
@@ -227,10 +227,10 @@ static rpc_status_t deserialize_aead_update_req(const struct call_param_buf *req
return rpc_status;
}
-static rpc_status_t serialize_aead_update_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_aead_update_resp(struct rpc_buffer *resp_buf,
const uint8_t *output, size_t output_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
@@ -242,40 +242,40 @@ static rpc_status_t serialize_aead_update_resp(struct call_param_buf *resp_buf,
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(out_record.length);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(out_record.length);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: aead_finish */
-static rpc_status_t deserialize_aead_finish_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_finish_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_finish_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_finish_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_aead_finish_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_aead_finish_resp(struct rpc_buffer *resp_buf,
const uint8_t *aeadtext, size_t aeadtext_len,
const uint8_t *tag, size_t tag_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
int encoded_tlv_count = 0;
- resp_buf->data_len = 0;
+ resp_buf->data_length = 0;
tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
@@ -286,7 +286,7 @@ static rpc_status_t serialize_aead_finish_resp(struct call_param_buf *resp_buf,
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len += tlv_required_space(out_record.length);
+ resp_buf->data_length += tlv_required_space(out_record.length);
++encoded_tlv_count;
}
@@ -296,31 +296,32 @@ static rpc_status_t serialize_aead_finish_resp(struct call_param_buf *resp_buf,
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len += tlv_required_space(out_record.length);
+ resp_buf->data_length += tlv_required_space(out_record.length);
++encoded_tlv_count;
}
/* Check that expected TLV records have been encoded */
- if (encoded_tlv_count == 2) rpc_status = TS_RPC_CALL_ACCEPTED;
+ if (encoded_tlv_count == 2)
+ rpc_status = RPC_SUCCESS;
return rpc_status;
}
/* Operation: aead_verify */
-static rpc_status_t deserialize_aead_verify_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_verify_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **tag, size_t *tag_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_verify_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_verify_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -328,7 +329,7 @@ static rpc_status_t deserialize_aead_verify_req(const struct call_param_buf *req
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_AEAD_VERIFY_IN_TAG_TAG, &decoded_record)) {
@@ -344,10 +345,10 @@ static rpc_status_t deserialize_aead_verify_req(const struct call_param_buf *req
return rpc_status;
}
-static rpc_status_t serialize_aead_verify_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_aead_verify_resp(struct rpc_buffer *resp_buf,
const uint8_t *plaintext, size_t plaintext_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
@@ -359,26 +360,26 @@ static rpc_status_t serialize_aead_verify_resp(struct call_param_buf *resp_buf,
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(out_record.length);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(out_record.length);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: aead_abort */
-static rpc_status_t deserialize_aead_abort_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_aead_abort_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_aead_abort_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_aead_abort_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/cipher/cipher_provider.c b/components/service/crypto/provider/extension/cipher/cipher_provider.c
index 8e7a86de7..ceecdee3b 100644
--- a/components/service/crypto/provider/extension/cipher/cipher_provider.c
+++ b/components/service/crypto/provider/extension/cipher/cipher_provider.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,12 +11,12 @@
#include <psa/crypto.h>
/* Service request handlers */
-static rpc_status_t cipher_setup_handler(void *context, struct call_req* req);
-static rpc_status_t cipher_generate_iv_handler(void *context, struct call_req* req);
-static rpc_status_t cipher_set_iv_handler(void *context, struct call_req* req);
-static rpc_status_t cipher_update_handler(void *context, struct call_req* req);
-static rpc_status_t cipher_finish_handler(void *context, struct call_req* req);
-static rpc_status_t cipher_abort_handler(void *context, struct call_req* req);
+static rpc_status_t cipher_setup_handler(void *context, struct rpc_request *req);
+static rpc_status_t cipher_generate_iv_handler(void *context, struct rpc_request *req);
+static rpc_status_t cipher_set_iv_handler(void *context, struct rpc_request *req);
+static rpc_status_t cipher_update_handler(void *context, struct rpc_request *req);
+static rpc_status_t cipher_finish_handler(void *context, struct rpc_request *req);
+static rpc_status_t cipher_abort_handler(void *context, struct rpc_request *req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
@@ -31,12 +31,14 @@ static const struct service_handler handler_table[] = {
void cipher_provider_init(struct cipher_provider *context)
{
+ const struct rpc_uuid nil_uuid = { 0 };
+
crypto_context_pool_init(&context->context_pool);
for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
context->serializers[encoding] = NULL;
- service_provider_init(&context->base_provider, context,
+ service_provider_init(&context->base_provider, context, &nil_uuid,
handler_table, sizeof(handler_table)/sizeof(struct service_handler));
}
@@ -53,21 +55,18 @@ void cipher_provider_register_serializer(struct cipher_provider *context,
}
static const struct cipher_provider_serializer* get_serializer(void *context,
- const struct call_req *req)
+ const struct rpc_request *req)
{
struct cipher_provider *this_instance = (struct cipher_provider*)context;
- const struct cipher_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
-
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+ unsigned int encoding = 0; /* No other encodings supported */
- return serializer;
+ return this_instance->serializers[encoding];
}
-static rpc_status_t cipher_setup_handler(void *context, struct call_req* req)
+static rpc_status_t cipher_setup_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct cipher_provider_serializer *serializer = get_serializer(context, req);
struct cipher_provider *this_instance = (struct cipher_provider*)context;
@@ -77,13 +76,13 @@ static rpc_status_t cipher_setup_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_cipher_setup_req(req_buf, &key_id, &alg);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
uint32_t op_handle;
struct crypto_context *crypto_context =
crypto_context_pool_alloc(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_CIPHER, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_CIPHER, req->source_id,
&op_handle);
if (crypto_context) {
@@ -92,36 +91,34 @@ static rpc_status_t cipher_setup_handler(void *context, struct call_req* req)
crypto_context->op.cipher = psa_cipher_operation_init();
- psa_status = (call_req_get_opcode(req) == TS_CRYPTO_OPCODE_CIPHER_ENCRYPT_SETUP) ?
+ psa_status = (req->opcode == TS_CRYPTO_OPCODE_CIPHER_ENCRYPT_SETUP) ?
psa_cipher_encrypt_setup(&crypto_context->op.cipher, key_id, alg) :
psa_cipher_decrypt_setup(&crypto_context->op.cipher, key_id, alg);
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_cipher_setup_resp(resp_buf, op_handle);
}
- if ((psa_status != PSA_SUCCESS) || (rpc_status != TS_RPC_CALL_ACCEPTED)) {
-
+ if ((psa_status != PSA_SUCCESS) || (rpc_status != RPC_SUCCESS))
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
- }
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
else {
/* Failed to allocate crypto context for transaction */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t cipher_generate_iv_handler(void *context, struct call_req* req)
+static rpc_status_t cipher_generate_iv_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct cipher_provider_serializer *serializer = get_serializer(context, req);
struct cipher_provider *this_instance = (struct cipher_provider*)context;
@@ -130,13 +127,13 @@ static rpc_status_t cipher_generate_iv_handler(void *context, struct call_req* r
if (serializer)
rpc_status = serializer->deserialize_cipher_generate_iv_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_CIPHER, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_CIPHER, req->source_id,
op_handle);
if (crypto_context) {
@@ -148,21 +145,21 @@ static rpc_status_t cipher_generate_iv_handler(void *context, struct call_req* r
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_cipher_generate_iv_resp(resp_buf, iv, iv_len);
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t cipher_set_iv_handler(void *context, struct call_req* req)
+static rpc_status_t cipher_set_iv_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct cipher_provider_serializer *serializer = get_serializer(context, req);
struct cipher_provider *this_instance = (struct cipher_provider*)context;
@@ -174,13 +171,13 @@ static rpc_status_t cipher_set_iv_handler(void *context, struct call_req* req)
rpc_status = serializer->deserialize_cipher_set_iv_req(req_buf, &op_handle,
&iv, &iv_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_CIPHER, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_CIPHER, req->source_id,
op_handle);
if (crypto_context) {
@@ -188,16 +185,16 @@ static rpc_status_t cipher_set_iv_handler(void *context, struct call_req* req)
psa_status = psa_cipher_set_iv(&crypto_context->op.cipher, iv, iv_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t cipher_update_handler(void *context, struct call_req* req)
+static rpc_status_t cipher_update_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct cipher_provider_serializer *serializer = get_serializer(context, req);
struct cipher_provider *this_instance = (struct cipher_provider*)context;
@@ -209,13 +206,13 @@ static rpc_status_t cipher_update_handler(void *context, struct call_req* req)
rpc_status = serializer->deserialize_cipher_update_req(req_buf, &op_handle,
&input, &input_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_CIPHER, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_CIPHER, req->source_id,
op_handle);
if (crypto_context) {
@@ -232,7 +229,7 @@ static rpc_status_t cipher_update_handler(void *context, struct call_req* req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_cipher_update_resp(resp_buf,
output, output_len);
}
@@ -245,16 +242,16 @@ static rpc_status_t cipher_update_handler(void *context, struct call_req* req)
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t cipher_finish_handler(void *context, struct call_req* req)
+static rpc_status_t cipher_finish_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct cipher_provider_serializer *serializer = get_serializer(context, req);
struct cipher_provider *this_instance = (struct cipher_provider*)context;
@@ -263,13 +260,13 @@ static rpc_status_t cipher_finish_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_cipher_finish_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_CIPHER, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_CIPHER, req->source_id,
op_handle);
if (crypto_context) {
@@ -281,23 +278,23 @@ static rpc_status_t cipher_finish_handler(void *context, struct call_req* req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_cipher_finish_resp(resp_buf, output, output_len);
- }
- crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ }
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t cipher_abort_handler(void *context, struct call_req* req)
+static rpc_status_t cipher_abort_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct cipher_provider_serializer *serializer = get_serializer(context, req);
struct cipher_provider *this_instance = (struct cipher_provider*)context;
@@ -306,7 +303,7 @@ static rpc_status_t cipher_abort_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_cipher_abort_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
/* Return success if operation is no longer active and
* doesn't need aborting.
@@ -315,7 +312,7 @@ static rpc_status_t cipher_abort_handler(void *context, struct call_req* req)
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_CIPHER, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_CIPHER, req->source_id,
op_handle);
if (crypto_context) {
@@ -324,7 +321,7 @@ static rpc_status_t cipher_abort_handler(void *context, struct call_req* req)
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/cipher/cipher_provider.h b/components/service/crypto/provider/extension/cipher/cipher_provider.h
index df2a27d11..be03a80a9 100644
--- a/components/service/crypto/provider/extension/cipher/cipher_provider.h
+++ b/components/service/crypto/provider/extension/cipher/cipher_provider.h
@@ -7,7 +7,7 @@
#ifndef CIPHER_PROVIDER_H
#define CIPHER_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include <service/common/provider/service_provider.h>
#include <service/crypto/provider/extension/cipher/serializer/cipher_provider_serializer.h>
#include <service/crypto/provider/crypto_context_pool.h>
diff --git a/components/service/crypto/provider/extension/cipher/serializer/cipher_provider_serializer.h b/components/service/crypto/provider/extension/cipher/serializer/cipher_provider_serializer.h
index ccc9b96d6..21169d94f 100644
--- a/components/service/crypto/provider/extension/cipher/serializer/cipher_provider_serializer.h
+++ b/components/service/crypto/provider/extension/cipher/serializer/cipher_provider_serializer.h
@@ -10,7 +10,7 @@
#include <stddef.h>
#include <stdint.h>
#include <psa/crypto.h>
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
/* Provides a common interface for parameter serialization operations
* for the cipher service provider.
@@ -18,42 +18,42 @@
struct cipher_provider_serializer {
/* Operation: cipher_setup */
- rpc_status_t (*deserialize_cipher_setup_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_cipher_setup_req)(const struct rpc_buffer *req_buf,
psa_key_id_t *id,
psa_algorithm_t *alg);
- rpc_status_t (*serialize_cipher_setup_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_cipher_setup_resp)(struct rpc_buffer *resp_buf,
uint32_t op_handle);
/* Operation: cipher_generate_iv */
- rpc_status_t (*deserialize_cipher_generate_iv_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_cipher_generate_iv_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
- rpc_status_t (*serialize_cipher_generate_iv_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_cipher_generate_iv_resp)(struct rpc_buffer *resp_buf,
const uint8_t *iv, size_t iv_len);
/* Operation: cipher_set_iv */
- rpc_status_t (*deserialize_cipher_set_iv_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_cipher_set_iv_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **iv, size_t *iv_len);
/* Operation: cipher_update */
- rpc_status_t (*deserialize_cipher_update_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_cipher_update_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **data, size_t *data_len);
- rpc_status_t (*serialize_cipher_update_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_cipher_update_resp)(struct rpc_buffer *resp_buf,
const uint8_t *data, size_t data_len);
/* Operation: cipher_finish */
- rpc_status_t (*deserialize_cipher_finish_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_cipher_finish_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
- rpc_status_t (*serialize_cipher_finish_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_cipher_finish_resp)(struct rpc_buffer *resp_buf,
const uint8_t *data, size_t data_len);
/* Operation: cipher_abort */
- rpc_status_t (*deserialize_cipher_abort_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_cipher_abort_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
};
diff --git a/components/service/crypto/provider/extension/cipher/serializer/packed-c/packedc_cipher_provider_serializer.c b/components/service/crypto/provider/extension/cipher/serializer/packed-c/packedc_cipher_provider_serializer.c
index 1acb165ef..eb9cce3bc 100644
--- a/components/service/crypto/provider/extension/cipher/serializer/packed-c/packedc_cipher_provider_serializer.c
+++ b/components/service/crypto/provider/extension/cipher/serializer/packed-c/packedc_cipher_provider_serializer.c
@@ -11,29 +11,29 @@
#include "packedc_cipher_provider_serializer.h"
/* Operation: cipher_setup */
-static rpc_status_t deserialize_cipher_setup_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_cipher_setup_req(const struct rpc_buffer *req_buf,
psa_key_id_t *id,
psa_algorithm_t *alg)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_cipher_setup_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_cipher_setup_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*id = recv_msg.key_id;
*alg = recv_msg.alg;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_cipher_setup_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_cipher_setup_resp(struct rpc_buffer *resp_buf,
uint32_t op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct ts_crypto_cipher_setup_out resp_msg;
size_t fixed_len = sizeof(struct ts_crypto_cipher_setup_out);
@@ -42,35 +42,35 @@ static rpc_status_t serialize_cipher_setup_resp(struct call_param_buf *resp_buf,
if (fixed_len <= resp_buf->size) {
memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: cipher_generate_iv */
-static rpc_status_t deserialize_cipher_generate_iv_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_cipher_generate_iv_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_cipher_generate_iv_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_cipher_generate_iv_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_cipher_generate_iv_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_cipher_generate_iv_resp(struct rpc_buffer *resp_buf,
const uint8_t *iv, size_t iv_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
@@ -82,28 +82,28 @@ static rpc_status_t serialize_cipher_generate_iv_resp(struct call_param_buf *res
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(iv_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(iv_len);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: cipher_set_iv */
-static rpc_status_t deserialize_cipher_set_iv_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_cipher_set_iv_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **iv, size_t *iv_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_cipher_set_iv_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_cipher_set_iv_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -111,7 +111,7 @@ static rpc_status_t deserialize_cipher_set_iv_req(const struct call_param_buf *r
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_CIPHER_SET_IV_IN_TAG_IV, &decoded_record)) {
@@ -128,20 +128,20 @@ static rpc_status_t deserialize_cipher_set_iv_req(const struct call_param_buf *r
}
/* Operation: cipher_update */
-static rpc_status_t deserialize_cipher_update_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_cipher_update_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
- const uint8_t **data, size_t *data_len)
+ const uint8_t **data, size_t *data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_cipher_update_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_cipher_update_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -149,97 +149,97 @@ static rpc_status_t deserialize_cipher_update_req(const struct call_param_buf *r
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_CIPHER_UPDATE_IN_TAG_DATA, &decoded_record)) {
*data = decoded_record.value;
- *data_len = decoded_record.length;
+ *data_length = decoded_record.length;
}
else {
/* Default to a zero length data */
- *data_len = 0;
+ *data_length = 0;
}
}
return rpc_status;
}
-static rpc_status_t serialize_cipher_update_resp(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len)
+static rpc_status_t serialize_cipher_update_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *data, size_t data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
out_record.tag = TS_CRYPTO_CIPHER_UPDATE_OUT_TAG_DATA;
- out_record.length = data_len;
+ out_record.length = data_length;
out_record.value = data;
tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(data_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(data_length);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: cipher_finish */
-static rpc_status_t deserialize_cipher_finish_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_cipher_finish_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_cipher_finish_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_cipher_finish_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_cipher_finish_resp(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len)
+static rpc_status_t serialize_cipher_finish_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *data, size_t data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
out_record.tag = TS_CRYPTO_CIPHER_FINISH_OUT_TAG_DATA;
- out_record.length = data_len;
+ out_record.length = data_length;
out_record.value = data;
tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(data_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(data_length);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: cipher_abort */
-static rpc_status_t deserialize_cipher_abort_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_cipher_abort_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_cipher_abort_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_cipher_abort_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/hash/hash_provider.c b/components/service/crypto/provider/extension/hash/hash_provider.c
index 2c560513f..1c4da5dcd 100644
--- a/components/service/crypto/provider/extension/hash/hash_provider.c
+++ b/components/service/crypto/provider/extension/hash/hash_provider.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,12 +11,12 @@
#include <psa/crypto.h>
/* Service request handlers */
-static rpc_status_t hash_setup_handler(void *context, struct call_req* req);
-static rpc_status_t hash_update_handler(void *context, struct call_req* req);
-static rpc_status_t hash_finish_handler(void *context, struct call_req* req);
-static rpc_status_t hash_abort_handler(void *context, struct call_req* req);
-static rpc_status_t hash_verify_handler(void *context, struct call_req* req);
-static rpc_status_t hash_clone_handler(void *context, struct call_req* req);
+static rpc_status_t hash_setup_handler(void *context, struct rpc_request *req);
+static rpc_status_t hash_update_handler(void *context, struct rpc_request *req);
+static rpc_status_t hash_finish_handler(void *context, struct rpc_request *req);
+static rpc_status_t hash_abort_handler(void *context, struct rpc_request *req);
+static rpc_status_t hash_verify_handler(void *context, struct rpc_request *req);
+static rpc_status_t hash_clone_handler(void *context, struct rpc_request *req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
@@ -30,12 +30,14 @@ static const struct service_handler handler_table[] = {
void hash_provider_init(struct hash_provider *context)
{
+ const struct rpc_uuid nil_uuid = { 0 };
+
crypto_context_pool_init(&context->context_pool);
for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
context->serializers[encoding] = NULL;
- service_provider_init(&context->base_provider, context,
+ service_provider_init(&context->base_provider, context, &nil_uuid,
handler_table, sizeof(handler_table)/sizeof(struct service_handler));
}
@@ -52,21 +54,18 @@ void hash_provider_register_serializer(struct hash_provider *context,
}
static const struct hash_provider_serializer* get_serializer(void *context,
- const struct call_req *req)
+ const struct rpc_request *req)
{
struct hash_provider *this_instance = (struct hash_provider*)context;
- const struct hash_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
-
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+ unsigned int encoding = 0; /* No other encodings supported */
- return serializer;
+ return this_instance->serializers[encoding];
}
-static rpc_status_t hash_setup_handler(void *context, struct call_req* req)
+static rpc_status_t hash_setup_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct hash_provider_serializer *serializer = get_serializer(context, req);
struct hash_provider *this_instance = (struct hash_provider*)context;
@@ -75,13 +74,13 @@ static rpc_status_t hash_setup_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_hash_setup_req(req_buf, &alg);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
uint32_t op_handle;
struct crypto_context *crypto_context =
crypto_context_pool_alloc(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_HASH, req->source_id,
&op_handle);
if (crypto_context) {
@@ -93,30 +92,28 @@ static rpc_status_t hash_setup_handler(void *context, struct call_req* req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_hash_setup_resp(resp_buf, op_handle);
}
- if ((psa_status != PSA_SUCCESS) || (rpc_status != TS_RPC_CALL_ACCEPTED)) {
-
+ if ((psa_status != PSA_SUCCESS) || (rpc_status != RPC_SUCCESS))
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
- }
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
else {
/* Failed to allocate crypto context for transaction */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t hash_update_handler(void *context, struct call_req* req)
+static rpc_status_t hash_update_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct hash_provider_serializer *serializer = get_serializer(context, req);
struct hash_provider *this_instance = (struct hash_provider*)context;
@@ -127,13 +124,13 @@ static rpc_status_t hash_update_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_hash_update_req(req_buf, &op_handle, &data, &data_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_HASH, req->source_id,
op_handle);
if (crypto_context) {
@@ -141,16 +138,16 @@ static rpc_status_t hash_update_handler(void *context, struct call_req* req)
psa_status = psa_hash_update(&crypto_context->op.hash, data, data_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t hash_finish_handler(void *context, struct call_req* req)
+static rpc_status_t hash_finish_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct hash_provider_serializer *serializer = get_serializer(context, req);
struct hash_provider *this_instance = (struct hash_provider*)context;
@@ -159,13 +156,13 @@ static rpc_status_t hash_finish_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_hash_finish_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_HASH, req->source_id,
op_handle);
if (crypto_context) {
@@ -177,23 +174,23 @@ static rpc_status_t hash_finish_handler(void *context, struct call_req* req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_hash_finish_resp(resp_buf, hash, hash_len);
- }
- crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ }
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t hash_abort_handler(void *context, struct call_req* req)
+static rpc_status_t hash_abort_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct hash_provider_serializer *serializer = get_serializer(context, req);
struct hash_provider *this_instance = (struct hash_provider*)context;
@@ -202,7 +199,7 @@ static rpc_status_t hash_abort_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_hash_abort_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
/* Return success if operation is no longer active and
* doesn't need aborting.
@@ -211,7 +208,7 @@ static rpc_status_t hash_abort_handler(void *context, struct call_req* req)
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_HASH, req->source_id,
op_handle);
if (crypto_context) {
@@ -220,16 +217,16 @@ static rpc_status_t hash_abort_handler(void *context, struct call_req* req)
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t hash_verify_handler(void *context, struct call_req* req)
+static rpc_status_t hash_verify_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct hash_provider_serializer *serializer = get_serializer(context, req);
struct hash_provider *this_instance = (struct hash_provider*)context;
@@ -240,30 +237,33 @@ static rpc_status_t hash_verify_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_hash_verify_req(req_buf, &op_handle, &hash, &hash_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_HASH, req->source_id,
op_handle);
if (crypto_context) {
psa_status = psa_hash_verify(&crypto_context->op.hash, hash, hash_len);
+
+ if (psa_status == PSA_SUCCESS)
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t hash_clone_handler(void *context, struct call_req* req)
+static rpc_status_t hash_clone_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct hash_provider_serializer *serializer = get_serializer(context, req);
struct hash_provider *this_instance = (struct hash_provider*)context;
@@ -272,13 +272,13 @@ static rpc_status_t hash_clone_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_hash_clone_req(req_buf, &source_op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *source_crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_HASH, req->source_id,
source_op_handle);
if (source_crypto_context) {
@@ -287,7 +287,7 @@ static rpc_status_t hash_clone_handler(void *context, struct call_req* req)
struct crypto_context *target_crypto_context = crypto_context_pool_alloc(
&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_HASH, req->source_id,
&target_op_handle);
if (target_crypto_context) {
@@ -299,13 +299,13 @@ static rpc_status_t hash_clone_handler(void *context, struct call_req* req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_hash_clone_resp(resp_buf, target_op_handle);
}
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/hash/hash_provider.h b/components/service/crypto/provider/extension/hash/hash_provider.h
index 917d1f186..2dad161a0 100644
--- a/components/service/crypto/provider/extension/hash/hash_provider.h
+++ b/components/service/crypto/provider/extension/hash/hash_provider.h
@@ -7,7 +7,7 @@
#ifndef HASH_PROVIDER_H
#define HASH_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include <service/common/provider/service_provider.h>
#include <service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h>
#include <service/crypto/provider/crypto_context_pool.h>
diff --git a/components/service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h b/components/service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h
index 1611e6e63..bfb4d8b98 100644
--- a/components/service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h
+++ b/components/service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h
@@ -10,7 +10,7 @@
#include <stddef.h>
#include <stdint.h>
#include <psa/crypto.h>
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
/* Provides a common interface for parameter serialization operations
* for the hash service provider.
@@ -18,38 +18,38 @@
struct hash_provider_serializer {
/* Operation: hash_setup */
- rpc_status_t (*deserialize_hash_setup_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_hash_setup_req)(const struct rpc_buffer *req_buf,
psa_algorithm_t *alg);
- rpc_status_t (*serialize_hash_setup_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_hash_setup_resp)(struct rpc_buffer *resp_buf,
uint32_t op_handle);
/* Operation: hash_update */
- rpc_status_t (*deserialize_hash_update_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_hash_update_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **data, size_t *data_len);
/* Operation: hash_finish */
- rpc_status_t (*deserialize_hash_finish_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_hash_finish_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
- rpc_status_t (*serialize_hash_finish_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_hash_finish_resp)(struct rpc_buffer *resp_buf,
const uint8_t *hash, size_t hash_len);
/* Operation: hash_abort */
- rpc_status_t (*deserialize_hash_abort_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_hash_abort_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
/* Operation: hash_verify */
- rpc_status_t (*deserialize_hash_verify_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_hash_verify_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **hash, size_t *hash_len);
/* Operation: hash_clone */
- rpc_status_t (*deserialize_hash_clone_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_hash_clone_req)(const struct rpc_buffer *req_buf,
uint32_t *source_op_handle);
- rpc_status_t (*serialize_hash_clone_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_hash_clone_resp)(struct rpc_buffer *resp_buf,
uint32_t target_op_handle);
};
diff --git a/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.c b/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.c
index ac0c35e47..6f131c535 100644
--- a/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.c
+++ b/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.c
@@ -11,27 +11,27 @@
#include "packedc_hash_provider_serializer.h"
/* Operation: hash_setup */
-static rpc_status_t deserialize_hash_setup_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_hash_setup_req(const struct rpc_buffer *req_buf,
psa_algorithm_t *alg)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_hash_setup_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_hash_setup_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*alg = recv_msg.alg;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_hash_setup_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_hash_setup_resp(struct rpc_buffer *resp_buf,
uint32_t op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct ts_crypto_hash_setup_out resp_msg;
size_t fixed_len = sizeof(struct ts_crypto_hash_setup_out);
@@ -40,28 +40,28 @@ static rpc_status_t serialize_hash_setup_resp(struct call_param_buf *resp_buf,
if (fixed_len <= resp_buf->size) {
memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: hash_update */
-static rpc_status_t deserialize_hash_update_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_hash_update_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
- const uint8_t **data, size_t *data_len)
+ const uint8_t **data, size_t *data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_hash_update_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_hash_update_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -69,16 +69,16 @@ static rpc_status_t deserialize_hash_update_req(const struct call_param_buf *req
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_HASH_UPDATE_IN_TAG_DATA, &decoded_record)) {
*data = decoded_record.value;
- *data_len = decoded_record.length;
+ *data_length = decoded_record.length;
}
else {
/* Default to a zero length data */
- *data_len = 0;
+ *data_length = 0;
}
}
@@ -86,27 +86,27 @@ static rpc_status_t deserialize_hash_update_req(const struct call_param_buf *req
}
/* Operation: hash_finish */
-static rpc_status_t deserialize_hash_finish_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_hash_finish_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_hash_finish_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_hash_finish_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_hash_finish_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_hash_finish_resp(struct rpc_buffer *resp_buf,
const uint8_t *hash, size_t hash_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
@@ -118,46 +118,46 @@ static rpc_status_t serialize_hash_finish_resp(struct call_param_buf *resp_buf,
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(hash_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(hash_len);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: hash_abort */
-static rpc_status_t deserialize_hash_abort_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_hash_abort_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_hash_abort_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_hash_abort_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: hash_verify */
-static rpc_status_t deserialize_hash_verify_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_hash_verify_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **hash, size_t *hash_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_hash_verify_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_hash_verify_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -165,7 +165,7 @@ static rpc_status_t deserialize_hash_verify_req(const struct call_param_buf *req
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_HASH_VERIFY_IN_TAG_HASH, &decoded_record)) {
@@ -182,27 +182,27 @@ static rpc_status_t deserialize_hash_verify_req(const struct call_param_buf *req
}
/* Operation: hash_clone */
-static rpc_status_t deserialize_hash_clone_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_hash_clone_req(const struct rpc_buffer *req_buf,
uint32_t *source_op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_hash_clone_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_hash_clone_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*source_op_handle = recv_msg.source_op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_hash_clone_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_hash_clone_resp(struct rpc_buffer *resp_buf,
uint32_t target_op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct ts_crypto_hash_clone_out resp_msg;
size_t fixed_len = sizeof(struct ts_crypto_hash_clone_out);
@@ -211,8 +211,8 @@ static rpc_status_t serialize_hash_clone_resp(struct call_param_buf *resp_buf,
if (fixed_len <= resp_buf->size) {
memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.c b/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.c
index dfb5b077c..9503f7ce1 100644
--- a/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.c
+++ b/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,16 +11,17 @@
#include <psa/crypto.h>
/* Service request handlers */
-static rpc_status_t key_derivation_setup_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_get_capacity_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_set_capacity_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_input_bytes_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_input_key_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_output_bytes_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_output_key_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_abort_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_key_agreement_handler(void *context, struct call_req* req);
-static rpc_status_t key_derivation_raw_key_agreement_handler(void *context, struct call_req* req);
+static rpc_status_t key_derivation_setup_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_get_capacity_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_set_capacity_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_input_bytes_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_input_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_output_bytes_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_output_key_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_abort_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_key_agreement_handler(void *context, struct rpc_request *req);
+static rpc_status_t key_derivation_raw_key_agreement_handler(void *context,
+ struct rpc_request *req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
@@ -38,12 +39,14 @@ static const struct service_handler handler_table[] = {
void key_derivation_provider_init(struct key_derivation_provider *context)
{
+ const struct rpc_uuid nil_uuid = { 0 };
+
crypto_context_pool_init(&context->context_pool);
for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
context->serializers[encoding] = NULL;
- service_provider_init(&context->base_provider, context,
+ service_provider_init(&context->base_provider, context, &nil_uuid,
handler_table, sizeof(handler_table)/sizeof(struct service_handler));
}
@@ -60,21 +63,18 @@ void key_derivation_provider_register_serializer(struct key_derivation_provider
}
static const struct key_derivation_provider_serializer* get_serializer(void *context,
- const struct call_req *req)
+ const struct rpc_request *req)
{
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
- const struct key_derivation_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
-
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+ unsigned int encoding = 0; /* No other encodings supported */
- return serializer;
+ return this_instance->serializers[encoding];
}
-static rpc_status_t key_derivation_setup_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_setup_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -83,13 +83,13 @@ static rpc_status_t key_derivation_setup_handler(void *context, struct call_req*
if (serializer)
rpc_status = serializer->deserialize_key_derivation_setup_req(req_buf, &alg);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
uint32_t op_handle;
struct crypto_context *crypto_context =
crypto_context_pool_alloc(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
&op_handle);
if (crypto_context) {
@@ -101,30 +101,28 @@ static rpc_status_t key_derivation_setup_handler(void *context, struct call_req*
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_key_derivation_setup_resp(resp_buf, op_handle);
}
- if ((psa_status != PSA_SUCCESS) || (rpc_status != TS_RPC_CALL_ACCEPTED)) {
-
+ if ((psa_status != PSA_SUCCESS) || (rpc_status != RPC_SUCCESS))
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
- }
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
else {
/* Failed to allocate crypto context for transaction */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t key_derivation_get_capacity_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_get_capacity_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -133,13 +131,13 @@ static rpc_status_t key_derivation_get_capacity_handler(void *context, struct ca
if (serializer)
rpc_status = serializer->deserialize_key_derivation_get_capacity_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
op_handle);
if (crypto_context) {
@@ -151,22 +149,22 @@ static rpc_status_t key_derivation_get_capacity_handler(void *context, struct ca
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_key_derivation_get_capacity_resp(resp_buf,
capacity);
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t key_derivation_set_capacity_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_set_capacity_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -177,13 +175,13 @@ static rpc_status_t key_derivation_set_capacity_handler(void *context, struct ca
rpc_status = serializer->deserialize_key_derivation_set_capacity_req(req_buf,
&op_handle, &capacity);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
op_handle);
if (crypto_context) {
@@ -192,16 +190,16 @@ static rpc_status_t key_derivation_set_capacity_handler(void *context, struct ca
capacity);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t key_derivation_input_bytes_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_input_bytes_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -214,13 +212,13 @@ static rpc_status_t key_derivation_input_bytes_handler(void *context, struct cal
rpc_status = serializer->deserialize_key_derivation_input_bytes_req(req_buf,
&op_handle, &step, &data, &data_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
op_handle);
if (crypto_context) {
@@ -229,16 +227,16 @@ static rpc_status_t key_derivation_input_bytes_handler(void *context, struct cal
step, data, data_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t key_derivation_input_key_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_input_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -250,7 +248,7 @@ static rpc_status_t key_derivation_input_key_handler(void *context, struct call_
rpc_status = serializer->deserialize_key_derivation_input_key_req(req_buf,
&op_handle, &step, &key_id);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_INVALID_HANDLE;
@@ -260,7 +258,7 @@ static rpc_status_t key_derivation_input_key_handler(void *context, struct call_
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
op_handle);
if (crypto_context) {
@@ -270,16 +268,16 @@ static rpc_status_t key_derivation_input_key_handler(void *context, struct call_
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t key_derivation_output_bytes_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_output_bytes_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -290,13 +288,13 @@ static rpc_status_t key_derivation_output_bytes_handler(void *context, struct ca
rpc_status = serializer->deserialize_key_derivation_output_bytes_req(req_buf,
&op_handle, &output_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
op_handle);
if (crypto_context) {
@@ -310,7 +308,7 @@ static rpc_status_t key_derivation_output_bytes_handler(void *context, struct ca
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_key_derivation_output_bytes_resp(resp_buf,
output, output_len);
}
@@ -323,16 +321,16 @@ static rpc_status_t key_derivation_output_bytes_handler(void *context, struct ca
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t key_derivation_output_key_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_output_key_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -343,13 +341,13 @@ static rpc_status_t key_derivation_output_key_handler(void *context, struct call
rpc_status = serializer->deserialize_key_derivation_output_key_req(req_buf,
&op_handle, &attributes);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
op_handle);
if (crypto_context) {
@@ -362,13 +360,13 @@ static rpc_status_t key_derivation_output_key_handler(void *context, struct call
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_key_derivation_output_key_resp(resp_buf,
key_id);
}
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
psa_reset_key_attributes(&attributes);
@@ -376,10 +374,10 @@ static rpc_status_t key_derivation_output_key_handler(void *context, struct call
return rpc_status;
}
-static rpc_status_t key_derivation_abort_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_abort_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -388,7 +386,7 @@ static rpc_status_t key_derivation_abort_handler(void *context, struct call_req*
if (serializer)
rpc_status = serializer->deserialize_key_derivation_abort_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
/* Return success if operation is no longer active and
* doesn't need aborting.
@@ -397,7 +395,7 @@ static rpc_status_t key_derivation_abort_handler(void *context, struct call_req*
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
op_handle);
if (crypto_context) {
@@ -406,16 +404,16 @@ static rpc_status_t key_derivation_abort_handler(void *context, struct call_req*
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t key_derivation_key_agreement_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_key_agreement_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
@@ -429,13 +427,13 @@ static rpc_status_t key_derivation_key_agreement_handler(void *context, struct c
rpc_status = serializer->deserialize_key_derivation_key_agreement_req(req_buf,
&op_handle, &step, &private_key_id, &peer_key, &peer_key_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_KEY_DERIVATION, req->source_id,
op_handle);
if (crypto_context) {
@@ -444,18 +442,17 @@ static rpc_status_t key_derivation_key_agreement_handler(void *context, struct c
step, private_key_id, peer_key, peer_key_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t key_derivation_raw_key_agreement_handler(void *context, struct call_req* req)
+static rpc_status_t key_derivation_raw_key_agreement_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct key_derivation_provider_serializer *serializer = get_serializer(context, req);
- struct key_derivation_provider *this_instance = (struct key_derivation_provider*)context;
psa_algorithm_t alg;
psa_key_id_t private_key_id;
@@ -466,7 +463,7 @@ static rpc_status_t key_derivation_raw_key_agreement_handler(void *context, stru
rpc_status = serializer->deserialize_key_derivation_raw_key_agreement_req(req_buf,
&alg, &private_key_id, &peer_key, &peer_key_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
size_t output_len;
uint8_t output[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE];
@@ -477,12 +474,12 @@ static rpc_status_t key_derivation_raw_key_agreement_handler(void *context, stru
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_key_derivation_raw_key_agreement_resp(resp_buf,
output, output_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.h b/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.h
index 1ac07f236..0abaed630 100644
--- a/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.h
+++ b/components/service/crypto/provider/extension/key_derivation/key_derivation_provider.h
@@ -7,7 +7,7 @@
#ifndef KEY_DERIVATION_PROVIDER_H
#define KEY_DERIVATION_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include <service/common/provider/service_provider.h>
#include <service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h>
#include <service/crypto/provider/crypto_context_pool.h>
diff --git a/components/service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h b/components/service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h
index 4bbeb419b..bff1a64b1 100644
--- a/components/service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h
+++ b/components/service/crypto/provider/extension/key_derivation/serializer/key_derivation_provider_serializer.h
@@ -10,7 +10,7 @@
#include <stddef.h>
#include <stdint.h>
#include <psa/crypto.h>
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
/* Provides a common interface for parameter serialization operations
* for the key_derivation service provider.
@@ -18,70 +18,70 @@
struct key_derivation_provider_serializer {
/* Operation: key_derivation_setup */
- rpc_status_t (*deserialize_key_derivation_setup_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_key_derivation_setup_req)(const struct rpc_buffer *req_buf,
psa_algorithm_t *alg);
- rpc_status_t (*serialize_key_derivation_setup_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_key_derivation_setup_resp)(struct rpc_buffer *resp_buf,
uint32_t op_handle);
/* Operation: key_derivation_get_capacity */
- rpc_status_t (*deserialize_key_derivation_get_capacity_req)(const struct call_param_buf *req_buf,
- uint32_t *op_handle);
+ rpc_status_t (*deserialize_key_derivation_get_capacity_req)(
+ const struct rpc_buffer *req_buf, uint32_t *op_handle);
- rpc_status_t (*serialize_key_derivation_get_capacity_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_key_derivation_get_capacity_resp)(struct rpc_buffer *resp_buf,
size_t capacity);
/* Operation: key_derivation_set_capacity */
- rpc_status_t (*deserialize_key_derivation_set_capacity_req)(const struct call_param_buf *req_buf,
- uint32_t *op_handle,
- size_t *capacity);
+ rpc_status_t (*deserialize_key_derivation_set_capacity_req)(
+ const struct rpc_buffer *req_buf, uint32_t *op_handle, size_t *capacity);
/* Operation: key_derivation_input_bytes */
- rpc_status_t (*deserialize_key_derivation_input_bytes_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_key_derivation_input_bytes_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
psa_key_derivation_step_t *step,
const uint8_t **data, size_t *data_len);
/* Operation: key_derivation_input_key */
- rpc_status_t (*deserialize_key_derivation_input_key_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_key_derivation_input_key_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
psa_key_derivation_step_t *step,
psa_key_id_t *key_id);
/* Operation: key_derivation_output_bytes */
- rpc_status_t (*deserialize_key_derivation_output_bytes_req)(const struct call_param_buf *req_buf,
- uint32_t *op_handle,
- size_t *output_len);
+ rpc_status_t (*deserialize_key_derivation_output_bytes_req)(
+ const struct rpc_buffer *req_buf, uint32_t *op_handle, size_t *output_len);
- rpc_status_t (*serialize_key_derivation_output_bytes_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_key_derivation_output_bytes_resp)(struct rpc_buffer *resp_buf,
const uint8_t *data, size_t data_len);
/* Operation: key_derivation_output_key */
- rpc_status_t (*deserialize_key_derivation_output_key_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_key_derivation_output_key_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
psa_key_attributes_t *attributes);
- rpc_status_t (*serialize_key_derivation_output_key_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_key_derivation_output_key_resp)(struct rpc_buffer *resp_buf,
psa_key_id_t key_id);
/* Operation: key_derivation_abort */
- rpc_status_t (*deserialize_key_derivation_abort_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_key_derivation_abort_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
/* Operation: key_derivation_key_agreement */
- rpc_status_t (*deserialize_key_derivation_key_agreement_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_key_derivation_key_agreement_req)(
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle,
psa_key_derivation_step_t *step,
psa_key_id_t *private_key_id,
const uint8_t **peer_key, size_t *peer_key_len);
/* Operation: key_derivation_raw_key_agreement */
- rpc_status_t (*deserialize_key_derivation_raw_key_agreement_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_key_derivation_raw_key_agreement_req)(
+ const struct rpc_buffer *req_buf,
psa_algorithm_t *alg,
psa_key_id_t *private_key_id,
const uint8_t **peer_key, size_t *peer_key_len);
- rpc_status_t (*serialize_key_derivation_raw_key_agreement_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_key_derivation_raw_key_agreement_resp)(struct rpc_buffer *resp_buf,
const uint8_t *output, size_t output_len);
};
diff --git a/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.c b/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.c
index 0d92f50f8..03bb3dcfd 100644
--- a/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.c
+++ b/components/service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.c
@@ -13,28 +13,28 @@
/* Operation: key_derivation_setup */
static rpc_status_t deserialize_key_derivation_setup_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
psa_algorithm_t *alg)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_setup_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_setup_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*alg = recv_msg.alg;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
static rpc_status_t serialize_key_derivation_setup_resp(
- struct call_param_buf *resp_buf,
+ struct rpc_buffer *resp_buf,
uint32_t op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct ts_crypto_key_derivation_setup_out resp_msg;
size_t fixed_len = sizeof(struct ts_crypto_key_derivation_setup_out);
@@ -43,8 +43,8 @@ static rpc_status_t serialize_key_derivation_setup_resp(
if (fixed_len <= resp_buf->size) {
memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
@@ -52,28 +52,28 @@ static rpc_status_t serialize_key_derivation_setup_resp(
/* Operation: key_derivation_get_capacity */
static rpc_status_t deserialize_key_derivation_get_capacity_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_get_capacity_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_get_capacity_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
static rpc_status_t serialize_key_derivation_get_capacity_resp(
- struct call_param_buf *resp_buf,
+ struct rpc_buffer *resp_buf,
size_t capacity)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct ts_crypto_key_derivation_get_capacity_out resp_msg;
size_t fixed_len = sizeof(struct ts_crypto_key_derivation_get_capacity_out);
@@ -82,8 +82,8 @@ static rpc_status_t serialize_key_derivation_get_capacity_resp(
if (fixed_len <= resp_buf->size) {
memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
@@ -91,20 +91,20 @@ static rpc_status_t serialize_key_derivation_get_capacity_resp(
/* Operation: key_derivation_set_capacity */
static rpc_status_t deserialize_key_derivation_set_capacity_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle,
size_t *capacity)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_set_capacity_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_set_capacity_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
*capacity = recv_msg.capacity;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
@@ -112,21 +112,21 @@ static rpc_status_t deserialize_key_derivation_set_capacity_req(
/* Operation: key_derivation_input_bytes */
static rpc_status_t deserialize_key_derivation_input_bytes_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle,
psa_key_derivation_step_t *step,
- const uint8_t **data, size_t *data_len)
+ const uint8_t **data, size_t *data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_input_bytes_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_input_bytes_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -135,17 +135,17 @@ static rpc_status_t deserialize_key_derivation_input_bytes_req(
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter,
TS_CRYPTO_KEY_DERIVATION_INPUT_BYTES_IN_TAG_DATA, &decoded_record)) {
*data = decoded_record.value;
- *data_len = decoded_record.length;
+ *data_length = decoded_record.length;
}
else {
/* Default to a zero length data */
- *data_len = 0;
+ *data_length = 0;
}
}
@@ -154,22 +154,22 @@ static rpc_status_t deserialize_key_derivation_input_bytes_req(
/* Operation: key_derivation_input_key */
static rpc_status_t deserialize_key_derivation_input_key_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle,
psa_key_derivation_step_t *step,
psa_key_id_t *key_id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_input_key_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_input_key_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
*step = recv_msg.step;
*key_id = recv_msg.key_id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
@@ -177,43 +177,43 @@ static rpc_status_t deserialize_key_derivation_input_key_req(
/* Operation: key_derivation_output_bytes */
static rpc_status_t deserialize_key_derivation_output_bytes_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle,
size_t *output_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_output_bytes_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_output_bytes_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
*output_len = recv_msg.output_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
static rpc_status_t serialize_key_derivation_output_bytes_resp(
- struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len)
+ struct rpc_buffer *resp_buf,
+ const uint8_t *data, size_t data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
out_record.tag = TS_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES_OUT_TAG_DATA;
- out_record.length = data_len;
+ out_record.length = data_length;
out_record.value = data;
tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(data_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(data_length);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
@@ -221,15 +221,15 @@ static rpc_status_t serialize_key_derivation_output_bytes_resp(
/* Operation: key_derivation_output_key */
static rpc_status_t deserialize_key_derivation_output_key_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle,
psa_key_attributes_t *attributes)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_output_key_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_output_key_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -237,17 +237,17 @@ static rpc_status_t deserialize_key_derivation_output_key_req(
packedc_crypto_provider_translate_key_attributes_from_proto(attributes,
&recv_msg.attributes);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
static rpc_status_t serialize_key_derivation_output_key_resp(
- struct call_param_buf *resp_buf,
+ struct rpc_buffer *resp_buf,
psa_key_id_t key_id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct ts_crypto_key_derivation_output_key_out resp_msg;
size_t fixed_len = sizeof(struct ts_crypto_key_derivation_output_key_out);
@@ -256,8 +256,8 @@ static rpc_status_t serialize_key_derivation_output_key_resp(
if (fixed_len <= resp_buf->size) {
memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
@@ -265,18 +265,18 @@ static rpc_status_t serialize_key_derivation_output_key_resp(
/* Operation: key_derivation_abort */
static rpc_status_t deserialize_key_derivation_abort_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_abort_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_abort_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
@@ -284,22 +284,22 @@ static rpc_status_t deserialize_key_derivation_abort_req(
/* Operation: key_derivation_key_agreement */
static rpc_status_t deserialize_key_derivation_key_agreement_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
uint32_t *op_handle,
psa_key_derivation_step_t *step,
psa_key_id_t *private_key_id,
const uint8_t **peer_key, size_t *peer_key_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_key_derivation_key_agreement_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_key_derivation_key_agreement_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -309,7 +309,7 @@ static rpc_status_t deserialize_key_derivation_key_agreement_req(
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter,
TS_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT_IN_TAG_PEER_KEY, &decoded_record)) {
@@ -328,21 +328,21 @@ static rpc_status_t deserialize_key_derivation_key_agreement_req(
/* Operation: key_derivation_raw_key_agreement */
static rpc_status_t deserialize_key_derivation_raw_key_agreement_req(
- const struct call_param_buf *req_buf,
+ const struct rpc_buffer *req_buf,
psa_algorithm_t *alg,
psa_key_id_t *private_key_id,
const uint8_t **peer_key, size_t *peer_key_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_raw_key_agreement_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_raw_key_agreement_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -351,7 +351,7 @@ static rpc_status_t deserialize_key_derivation_raw_key_agreement_req(
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter,
TS_CRYPTO_RAW_KEY_AGREEMENT_IN_TAG_PEER_KEY, &decoded_record)) {
@@ -369,10 +369,10 @@ static rpc_status_t deserialize_key_derivation_raw_key_agreement_req(
}
static rpc_status_t serialize_key_derivation_raw_key_agreement_resp(
- struct call_param_buf *resp_buf,
+ struct rpc_buffer *resp_buf,
const uint8_t *output, size_t output_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
@@ -384,8 +384,8 @@ static rpc_status_t serialize_key_derivation_raw_key_agreement_resp(
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(output_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(output_len);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/mac/mac_provider.c b/components/service/crypto/provider/extension/mac/mac_provider.c
index 96fe4cf3d..1e2081e88 100644
--- a/components/service/crypto/provider/extension/mac/mac_provider.c
+++ b/components/service/crypto/provider/extension/mac/mac_provider.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,11 +11,11 @@
#include <psa/crypto.h>
/* Service request handlers */
-static rpc_status_t mac_setup_handler(void *context, struct call_req* req);
-static rpc_status_t mac_update_handler(void *context, struct call_req* req);
-static rpc_status_t mac_sign_finish_handler(void *context, struct call_req* req);
-static rpc_status_t mac_verify_finish_handler(void *context, struct call_req* req);
-static rpc_status_t mac_abort_handler(void *context, struct call_req* req);
+static rpc_status_t mac_setup_handler(void *context, struct rpc_request *req);
+static rpc_status_t mac_update_handler(void *context, struct rpc_request *req);
+static rpc_status_t mac_sign_finish_handler(void *context, struct rpc_request *req);
+static rpc_status_t mac_verify_finish_handler(void *context, struct rpc_request *req);
+static rpc_status_t mac_abort_handler(void *context, struct rpc_request *req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
@@ -29,12 +29,14 @@ static const struct service_handler handler_table[] = {
void mac_provider_init(struct mac_provider *context)
{
+ const struct rpc_uuid nil_uuid = { 0 };
+
crypto_context_pool_init(&context->context_pool);
for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
context->serializers[encoding] = NULL;
- service_provider_init(&context->base_provider, context,
+ service_provider_init(&context->base_provider, context, &nil_uuid,
handler_table, sizeof(handler_table)/sizeof(struct service_handler));
}
@@ -51,21 +53,18 @@ void mac_provider_register_serializer(struct mac_provider *context,
}
static const struct mac_provider_serializer* get_serializer(void *context,
- const struct call_req *req)
+ const struct rpc_request *req)
{
struct mac_provider *this_instance = (struct mac_provider*)context;
- const struct mac_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
-
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+ unsigned int encoding = 0; /* No other encodings supported */
- return serializer;
+ return this_instance->serializers[encoding];
}
-static rpc_status_t mac_setup_handler(void *context, struct call_req* req)
+static rpc_status_t mac_setup_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct mac_provider_serializer *serializer = get_serializer(context, req);
struct mac_provider *this_instance = (struct mac_provider*)context;
@@ -75,13 +74,13 @@ static rpc_status_t mac_setup_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_mac_setup_req(req_buf, &key_id, &alg);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
uint32_t op_handle;
struct crypto_context *crypto_context =
crypto_context_pool_alloc(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_MAC, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_MAC, req->source_id,
&op_handle);
if (crypto_context) {
@@ -89,36 +88,34 @@ static rpc_status_t mac_setup_handler(void *context, struct call_req* req)
crypto_context->op.mac = psa_mac_operation_init();
psa_status_t psa_status =
- (call_req_get_opcode(req) == TS_CRYPTO_OPCODE_MAC_SIGN_SETUP) ?
+ (req->opcode == TS_CRYPTO_OPCODE_MAC_SIGN_SETUP) ?
psa_mac_sign_setup(&crypto_context->op.mac, key_id, alg) :
psa_mac_verify_setup(&crypto_context->op.mac, key_id, alg);
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_mac_setup_resp(resp_buf, op_handle);
}
- if ((psa_status != PSA_SUCCESS) || (rpc_status != TS_RPC_CALL_ACCEPTED)) {
-
+ if ((psa_status != PSA_SUCCESS) || (rpc_status != RPC_SUCCESS))
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
- }
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
else {
/* Failed to allocate crypto context for transaction */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
}
}
return rpc_status;
}
-static rpc_status_t mac_update_handler(void *context, struct call_req* req)
+static rpc_status_t mac_update_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct mac_provider_serializer *serializer = get_serializer(context, req);
struct mac_provider *this_instance = (struct mac_provider*)context;
@@ -129,13 +126,13 @@ static rpc_status_t mac_update_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_mac_update_req(req_buf, &op_handle, &data, &data_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_MAC, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_MAC, req->source_id,
op_handle);
if (crypto_context) {
@@ -143,16 +140,16 @@ static rpc_status_t mac_update_handler(void *context, struct call_req* req)
psa_status = psa_mac_update(&crypto_context->op.mac, data, data_len);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t mac_sign_finish_handler(void *context, struct call_req* req)
+static rpc_status_t mac_sign_finish_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct mac_provider_serializer *serializer = get_serializer(context, req);
struct mac_provider *this_instance = (struct mac_provider*)context;
@@ -161,13 +158,13 @@ static rpc_status_t mac_sign_finish_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_mac_sign_finish_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_MAC, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_MAC, req->source_id,
op_handle);
if (crypto_context) {
@@ -179,23 +176,23 @@ static rpc_status_t mac_sign_finish_handler(void *context, struct call_req* req)
if (psa_status == PSA_SUCCESS) {
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ struct rpc_buffer *resp_buf = &req->response;
rpc_status = serializer->serialize_mac_sign_finish_resp(resp_buf, mac, mac_len);
- }
- crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ }
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t mac_verify_finish_handler(void *context, struct call_req* req)
+static rpc_status_t mac_verify_finish_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct mac_provider_serializer *serializer = get_serializer(context, req);
struct mac_provider *this_instance = (struct mac_provider*)context;
@@ -207,32 +204,35 @@ static rpc_status_t mac_verify_finish_handler(void *context, struct call_req* re
rpc_status = serializer->deserialize_mac_verify_finish_req(req_buf,
&op_handle, &mac, &mac_len);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
psa_status_t psa_status = PSA_ERROR_BAD_STATE;
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_MAC, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_MAC, req->source_id,
op_handle);
if (crypto_context) {
psa_status = psa_mac_verify_finish(&crypto_context->op.mac, mac, mac_len);
- crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ if (psa_status == PSA_SUCCESS) {
+
+ crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+ }
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
}
-static rpc_status_t mac_abort_handler(void *context, struct call_req* req)
+static rpc_status_t mac_abort_handler(void *context, struct rpc_request *req)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
const struct mac_provider_serializer *serializer = get_serializer(context, req);
struct mac_provider *this_instance = (struct mac_provider*)context;
@@ -241,7 +241,7 @@ static rpc_status_t mac_abort_handler(void *context, struct call_req* req)
if (serializer)
rpc_status = serializer->deserialize_mac_abort_req(req_buf, &op_handle);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
/* Return success if operation is no longer active and
* doesn't need aborting.
@@ -250,7 +250,7 @@ static rpc_status_t mac_abort_handler(void *context, struct call_req* req)
struct crypto_context *crypto_context =
crypto_context_pool_find(&this_instance->context_pool,
- CRYPTO_CONTEXT_OP_ID_MAC, call_req_get_caller_id(req),
+ CRYPTO_CONTEXT_OP_ID_MAC, req->source_id,
op_handle);
if (crypto_context) {
@@ -259,7 +259,7 @@ static rpc_status_t mac_abort_handler(void *context, struct call_req* req)
crypto_context_pool_free(&this_instance->context_pool, crypto_context);
}
- call_req_set_opstatus(req, psa_status);
+ req->service_status = psa_status;
}
return rpc_status;
diff --git a/components/service/crypto/provider/extension/mac/mac_provider.h b/components/service/crypto/provider/extension/mac/mac_provider.h
index 5e3cbe210..d987f5ab0 100644
--- a/components/service/crypto/provider/extension/mac/mac_provider.h
+++ b/components/service/crypto/provider/extension/mac/mac_provider.h
@@ -7,7 +7,7 @@
#ifndef MAC_PROVIDER_H
#define MAC_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include <service/common/provider/service_provider.h>
#include <service/crypto/provider/extension/mac/serializer/mac_provider_serializer.h>
#include <service/crypto/provider/crypto_context_pool.h>
diff --git a/components/service/crypto/provider/extension/mac/serializer/mac_provider_serializer.h b/components/service/crypto/provider/extension/mac/serializer/mac_provider_serializer.h
index 3f5e5c68b..0ad046514 100644
--- a/components/service/crypto/provider/extension/mac/serializer/mac_provider_serializer.h
+++ b/components/service/crypto/provider/extension/mac/serializer/mac_provider_serializer.h
@@ -10,7 +10,7 @@
#include <stddef.h>
#include <stdint.h>
#include <psa/crypto.h>
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
/* Provides a common interface for parameter serialization operations
* for the mac service provider.
@@ -18,32 +18,32 @@
struct mac_provider_serializer {
/* Operation: mac_setup */
- rpc_status_t (*deserialize_mac_setup_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_mac_setup_req)(const struct rpc_buffer *req_buf,
psa_key_id_t *key_id,
psa_algorithm_t *alg);
- rpc_status_t (*serialize_mac_setup_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_mac_setup_resp)(struct rpc_buffer *resp_buf,
uint32_t op_handle);
/* Operation: mac_update */
- rpc_status_t (*deserialize_mac_update_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_mac_update_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **data, size_t *data_len);
/* Operation: mac_sign_finish */
- rpc_status_t (*deserialize_mac_sign_finish_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_mac_sign_finish_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
- rpc_status_t (*serialize_mac_sign_finish_resp)(struct call_param_buf *resp_buf,
+ rpc_status_t (*serialize_mac_sign_finish_resp)(struct rpc_buffer *resp_buf,
const uint8_t *mac, size_t mac_len);
/* Operation: mac_verify_finish */
- rpc_status_t (*deserialize_mac_verify_finish_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_mac_verify_finish_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **mac, size_t *mac_len);
/* Operation: mac_abort */
- rpc_status_t (*deserialize_mac_abort_req)(const struct call_param_buf *req_buf,
+ rpc_status_t (*deserialize_mac_abort_req)(const struct rpc_buffer *req_buf,
uint32_t *op_handle);
};
diff --git a/components/service/crypto/provider/extension/mac/serializer/packed-c/packedc_mac_provider_serializer.c b/components/service/crypto/provider/extension/mac/serializer/packed-c/packedc_mac_provider_serializer.c
index fa3a2c925..a82b98dc1 100644
--- a/components/service/crypto/provider/extension/mac/serializer/packed-c/packedc_mac_provider_serializer.c
+++ b/components/service/crypto/provider/extension/mac/serializer/packed-c/packedc_mac_provider_serializer.c
@@ -11,29 +11,29 @@
#include "packedc_mac_provider_serializer.h"
/* Operation: mac_setup */
-static rpc_status_t deserialize_mac_setup_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_mac_setup_req(const struct rpc_buffer *req_buf,
psa_key_id_t *key_id,
psa_algorithm_t *alg)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_mac_setup_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_mac_setup_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*key_id = recv_msg.key_id;
*alg = recv_msg.alg;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_mac_setup_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_mac_setup_resp(struct rpc_buffer *resp_buf,
uint32_t op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct ts_crypto_mac_setup_out resp_msg;
size_t fixed_len = sizeof(struct ts_crypto_mac_setup_out);
@@ -42,28 +42,28 @@ static rpc_status_t serialize_mac_setup_resp(struct call_param_buf *resp_buf,
if (fixed_len <= resp_buf->size) {
memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: mac_update */
-static rpc_status_t deserialize_mac_update_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_mac_update_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
- const uint8_t **data, size_t *data_len)
+ const uint8_t **data, size_t *data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_mac_update_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_mac_update_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -71,16 +71,16 @@ static rpc_status_t deserialize_mac_update_req(const struct call_param_buf *req_
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_MAC_UPDATE_IN_TAG_DATA, &decoded_record)) {
*data = decoded_record.value;
- *data_len = decoded_record.length;
+ *data_length = decoded_record.length;
}
else {
/* Default to a zero length data */
- *data_len = 0;
+ *data_length = 0;
}
}
@@ -88,27 +88,27 @@ static rpc_status_t deserialize_mac_update_req(const struct call_param_buf *req_
}
/* Operation: mac_finish */
-static rpc_status_t deserialize_mac_sign_finish_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_mac_sign_finish_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_mac_sign_finish_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_mac_sign_finish_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
-static rpc_status_t serialize_mac_sign_finish_resp(struct call_param_buf *resp_buf,
+static rpc_status_t serialize_mac_sign_finish_resp(struct rpc_buffer *resp_buf,
const uint8_t *mac, size_t mac_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
struct tlv_iterator resp_iter;
struct tlv_record out_record;
@@ -120,28 +120,28 @@ static rpc_status_t serialize_mac_sign_finish_resp(struct call_param_buf *resp_b
if (tlv_encode(&resp_iter, &out_record)) {
- resp_buf->data_len = tlv_required_space(mac_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ resp_buf->data_length = tlv_required_space(mac_len);
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
}
/* Operation: mac_verify_finish */
-static rpc_status_t deserialize_mac_verify_finish_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_mac_verify_finish_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle,
const uint8_t **mac, size_t *mac_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_mac_verify_finish_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_mac_verify_finish_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
struct tlv_const_iterator req_iter;
struct tlv_record decoded_record;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
@@ -149,7 +149,7 @@ static rpc_status_t deserialize_mac_verify_finish_req(const struct call_param_bu
tlv_const_iterator_begin(&req_iter,
(uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
+ req_buf->data_length - expected_fixed_len);
if (tlv_find_decode(&req_iter, TS_CRYPTO_MAC_SIGN_FINISH_OUT_TAG_MAC, &decoded_record)) {
@@ -166,18 +166,18 @@ static rpc_status_t deserialize_mac_verify_finish_req(const struct call_param_bu
}
/* Operation: mac_abort */
-static rpc_status_t deserialize_mac_abort_req(const struct call_param_buf *req_buf,
+static rpc_status_t deserialize_mac_abort_req(const struct rpc_buffer *req_buf,
uint32_t *op_handle)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
struct ts_crypto_mac_abort_in recv_msg;
size_t expected_fixed_len = sizeof(struct ts_crypto_mac_abort_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
memcpy(&recv_msg, req_buf->data, expected_fixed_len);
*op_handle = recv_msg.op_handle;
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ rpc_status = RPC_SUCCESS;
}
return rpc_status;
diff --git a/components/service/crypto/provider/serializer/crypto_provider_serializer.h b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
index 68940cae7..1a0ce3cd5 100644
--- a/components/service/crypto/provider/serializer/crypto_provider_serializer.h
+++ b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,10 +7,11 @@
#ifndef CRYPTO_PROVIDER_SERIALIZER_H
#define CRYPTO_PROVIDER_SERIALIZER_H
+#include <psa/crypto.h>
#include <stddef.h>
#include <stdint.h>
-#include <psa/crypto.h>
-#include <rpc/common/endpoint/rpc_interface.h>
+
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
/* Provides a common interface for parameter serialization operations
* for the crypto service provider. Allows alternative serialization
@@ -19,103 +20,112 @@
* implement this interface.
*/
struct crypto_provider_serializer {
-
- /* Returns the maximum deserialized parameter size that could
+ /* Returns the maximum deserialized parameter size that could
* be encoded in a request buffer. Used for determining worst-case
* buffer size without having to actually deserialize the message.
*/
- size_t (*max_deserialised_parameter_size)(const struct call_param_buf *req_buf);
-
- /* Operation: generate_key */
- rpc_status_t (*deserialize_generate_key_req)(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes);
-
- rpc_status_t (*serialize_generate_key_resp)(struct call_param_buf *resp_buf,
- psa_key_id_t id);
-
- /* Operation: destroy_key */
- rpc_status_t (*deserialize_destroy_key_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id);
-
- /* Operation: export_key */
- rpc_status_t (*deserialize_export_key_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id);
-
- rpc_status_t (*serialize_export_key_resp)(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len);
-
- /* Operation: export_public_key */
- rpc_status_t (*deserialize_export_public_key_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id);
-
- rpc_status_t (*serialize_export_public_key_resp)(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len);
-
- /* Operation: import_key */
- rpc_status_t (*deserialize_import_key_req)(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes,
- uint8_t *data, size_t *data_len);
-
- rpc_status_t (*serialize_import_key_resp)(struct call_param_buf *resp_buf,
- psa_key_id_t id);
-
- /* Operation: copy_key */
- rpc_status_t (*deserialize_copy_key_req)(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes,
- psa_key_id_t *source_id);
-
- rpc_status_t (*serialize_copy_key_resp)(struct call_param_buf *resp_buf,
- psa_key_id_t target_id);
-
- /* Operation: purge_key */
- rpc_status_t (*deserialize_purge_key_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id);
-
- /* Operation: get_key_attributes */
- rpc_status_t (*deserialize_get_key_attributes_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id);
-
- rpc_status_t (*serialize_get_key_attributes_resp)(struct call_param_buf *resp_buf,
- const psa_key_attributes_t *attributes);
-
- /* Operation: sign_hash */
- rpc_status_t (*deserialize_sign_hash_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *hash, size_t *hash_len);
-
- rpc_status_t (*serialize_sign_hash_resp)(struct call_param_buf *resp_buf,
- const uint8_t *sig, size_t sig_len);
-
- /* Operation: verify_hash */
- rpc_status_t (*deserialize_verify_hash_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *hash, size_t *hash_len,
- uint8_t *sig, size_t *sig_len);
-
- /* Operation: asymmetric_decrypt */
- rpc_status_t (*deserialize_asymmetric_decrypt_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *ciphertext, size_t *ciphertext_len,
- uint8_t *salt, size_t *salt_len);
-
- rpc_status_t (*serialize_asymmetric_decrypt_resp)(struct call_param_buf *resp_buf,
- const uint8_t *plaintext, size_t plaintext_len);
-
- /* Operation: asymmetric_encrypt */
- rpc_status_t (*deserialize_asymmetric_encrypt_req)(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *plaintext, size_t *plaintext_len,
- uint8_t *salt, size_t *salt_len);
-
- rpc_status_t (*serialize_asymmetric_encrypt_resp)(struct call_param_buf *resp_buf,
- const uint8_t *ciphertext, size_t ciphertext_len);
-
- /* Operation: generate_random */
- rpc_status_t (*deserialize_generate_random_req)(const struct call_param_buf *req_buf,
- size_t *size);
-
- rpc_status_t (*serialize_generate_random_resp)(struct call_param_buf *resp_buf,
- const uint8_t *output, size_t output_len);
+ size_t (*max_deserialised_parameter_size)(const struct rpc_buffer *req_buf);
+
+ /* Operation: generate_key */
+ rpc_status_t (*deserialize_generate_key_req)(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes);
+
+ rpc_status_t (*serialize_generate_key_resp)(struct rpc_buffer *resp_buf, psa_key_id_t id);
+
+ /* Operation: destroy_key */
+ rpc_status_t (*deserialize_destroy_key_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id);
+
+ /* Operation: export_key */
+ rpc_status_t (*deserialize_export_key_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id);
+
+ rpc_status_t (*serialize_export_key_resp)(struct rpc_buffer *resp_buf, const uint8_t *data,
+ size_t data_len);
+
+ /* Operation: export_public_key */
+ rpc_status_t (*deserialize_export_public_key_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id);
+
+ rpc_status_t (*serialize_export_public_key_resp)(struct rpc_buffer *resp_buf,
+ const uint8_t *data, size_t data_len);
+
+ /* Operation: import_key */
+ rpc_status_t (*deserialize_import_key_req)(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes, uint8_t *data,
+ size_t *data_len);
+
+ rpc_status_t (*serialize_import_key_resp)(struct rpc_buffer *resp_buf, psa_key_id_t id);
+
+ /* Operation: copy_key */
+ rpc_status_t (*deserialize_copy_key_req)(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes,
+ psa_key_id_t *source_id);
+
+ rpc_status_t (*serialize_copy_key_resp)(struct rpc_buffer *resp_buf,
+ psa_key_id_t target_id);
+
+ /* Operation: purge_key */
+ rpc_status_t (*deserialize_purge_key_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id);
+
+ /* Operation: get_key_attributes */
+ rpc_status_t (*deserialize_get_key_attributes_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id);
+
+ rpc_status_t (*serialize_get_key_attributes_resp)(struct rpc_buffer *resp_buf,
+ const psa_key_attributes_t *attributes);
+
+ /* Operation: sign_hash */
+ rpc_status_t (*deserialize_asymmetric_sign_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *hash, size_t *hash_len);
+
+ rpc_status_t (*serialize_asymmetric_sign_resp)(struct rpc_buffer *resp_buf,
+ const uint8_t *sig, size_t sig_len);
+
+ /* Operation: verify_hash */
+ rpc_status_t (*deserialize_asymmetric_verify_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *hash, size_t *hash_len,
+ uint8_t *sig, size_t *sig_len);
+
+ /* Operation: asymmetric_decrypt */
+ rpc_status_t (*deserialize_asymmetric_decrypt_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *ciphertext,
+ size_t *ciphertext_len, uint8_t *salt,
+ size_t *salt_len);
+
+ rpc_status_t (*serialize_asymmetric_decrypt_resp)(struct rpc_buffer *resp_buf,
+ const uint8_t *plaintext,
+ size_t plaintext_len);
+
+ /* Operation: asymmetric_encrypt */
+ rpc_status_t (*deserialize_asymmetric_encrypt_req)(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *plaintext,
+ size_t *plaintext_len, uint8_t *salt,
+ size_t *salt_len);
+
+ rpc_status_t (*serialize_asymmetric_encrypt_resp)(struct rpc_buffer *resp_buf,
+ const uint8_t *ciphertext,
+ size_t ciphertext_len);
+
+ /* Operation: generate_random */
+ rpc_status_t (*deserialize_generate_random_req)(const struct rpc_buffer *req_buf,
+ size_t *size);
+
+ rpc_status_t (*serialize_generate_random_resp)(struct rpc_buffer *resp_buf,
+ const uint8_t *output, size_t output_len);
+
+ /* Operation: verify_pkcs7_signature */
+ rpc_status_t (*deserialize_verify_pkcs7_signature_req)(struct rpc_buffer *req_buf,
+ uint8_t *signature_cert,
+ uint64_t *signature_cert_len,
+ uint8_t *hash, uint64_t *hash_len,
+ uint8_t *public_key_cert,
+ uint64_t *public_key_cert_len);
};
#endif /* CRYPTO_PROVIDER_SERIALIZER_H */
diff --git a/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c b/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c
index c70db865a..f59173d1e 100644
--- a/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c
+++ b/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c
@@ -1,710 +1,710 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <string.h>
-#include <stdlib.h>
+#include "packedc_crypto_provider_serializer.h"
+
#include <common/tlv/tlv.h>
-#include <psa/crypto.h>
#include <protocols/rpc/common/packed-c/status.h>
-#include <protocols/service/crypto/packed-c/key_attributes.h>
#include <protocols/service/crypto/packed-c/asymmetric_decrypt.h>
#include <protocols/service/crypto/packed-c/asymmetric_encrypt.h>
+#include <protocols/service/crypto/packed-c/copy_key.h>
#include <protocols/service/crypto/packed-c/destroy_key.h>
#include <protocols/service/crypto/packed-c/export_key.h>
#include <protocols/service/crypto/packed-c/export_public_key.h>
#include <protocols/service/crypto/packed-c/generate_key.h>
#include <protocols/service/crypto/packed-c/generate_random.h>
+#include <protocols/service/crypto/packed-c/get_key_attributes.h>
#include <protocols/service/crypto/packed-c/import_key.h>
-#include <protocols/service/crypto/packed-c/copy_key.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
#include <protocols/service/crypto/packed-c/purge_key.h>
-#include <protocols/service/crypto/packed-c/get_key_attributes.h>
#include <protocols/service/crypto/packed-c/sign_hash.h>
#include <protocols/service/crypto/packed-c/verify_hash.h>
-#include "packedc_crypto_provider_serializer.h"
+#include <protocols/service/crypto/packed-c/verify_pkcs7_signature.h>
+#include <psa/crypto.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "packedc_key_attributes_translator.h"
/* Returns the maximum possible deserialized parameter size for a packed-c encoded message. */
-static size_t max_deserialised_parameter_size(const struct call_param_buf *req_buf)
+static size_t max_deserialised_parameter_size(const struct rpc_buffer *req_buf)
{
- /*
- * Assume that a deserialized parameter must be the same size or smaller than the
- * entire serialized message.
- */
- return req_buf->data_len;
+ /*
+ * Assume that a deserialized parameter must be the same size or smaller than the
+ * entire serialized message.
+ */
+ return req_buf->data_length;
}
/* Operation: generate_key */
-static rpc_status_t deserialize_generate_key_req(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes)
+static rpc_status_t deserialize_generate_key_req(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_generate_key_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_generate_key_in);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_generate_key_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_generate_key_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ packedc_crypto_provider_translate_key_attributes_from_proto(attributes,
+ &recv_msg.attributes);
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- packedc_crypto_provider_translate_key_attributes_from_proto(attributes,
- &recv_msg.attributes);
+ rpc_status = RPC_SUCCESS;
+ }
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_generate_key_resp(struct call_param_buf *resp_buf,
- psa_key_id_t id)
+static rpc_status_t serialize_generate_key_resp(struct rpc_buffer *resp_buf, psa_key_id_t id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct ts_crypto_generate_key_out resp_msg;
- size_t fixed_len = sizeof(struct ts_crypto_generate_key_out);
-
- resp_msg.id = id;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_crypto_generate_key_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_crypto_generate_key_out);
- if (fixed_len <= resp_buf->size) {
+ resp_msg.id = id;
- memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (fixed_len <= resp_buf->size) {
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: destroy_key */
-static rpc_status_t deserialize_destroy_key_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_destroy_key_req(const struct rpc_buffer *req_buf, psa_key_id_t *id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_destroy_key_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_destroy_key_in);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_destroy_key_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_destroy_key_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *id = recv_msg.id;
+ rpc_status = RPC_SUCCESS;
+ }
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- *id = recv_msg.id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
+ return rpc_status;
}
/* Operation: export_key */
-static rpc_status_t deserialize_export_key_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_export_key_req(const struct rpc_buffer *req_buf, psa_key_id_t *id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_export_key_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_export_key_in);
-
- if (expected_fixed_len <= req_buf->data_len) {
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_export_key_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_export_key_in);
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- *id = recv_msg.id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (expected_fixed_len <= req_buf->data_length) {
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *id = recv_msg.id;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_export_key_resp(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len)
+static rpc_status_t serialize_export_key_resp(struct rpc_buffer *resp_buf, const uint8_t *data,
+ size_t data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct tlv_iterator resp_iter;
-
- struct tlv_record key_record;
- key_record.tag = TS_CRYPTO_EXPORT_KEY_OUT_TAG_DATA;
- key_record.length = data_len;
- key_record.value = data;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter;
+ struct tlv_record key_record;
- tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+ key_record.tag = TS_CRYPTO_EXPORT_KEY_OUT_TAG_DATA;
+ key_record.length = data_length;
+ key_record.value = data;
- if (tlv_encode(&resp_iter, &key_record)) {
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
- resp_buf->data_len = tlv_required_space(data_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (tlv_encode(&resp_iter, &key_record)) {
+ resp_buf->data_length = tlv_required_space(data_length);
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: export_public_key */
-static rpc_status_t deserialize_export_public_key_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_export_public_key_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_export_public_key_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_export_public_key_in);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_export_public_key_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_export_public_key_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *id = recv_msg.id;
+ rpc_status = RPC_SUCCESS;
+ }
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- *id = recv_msg.id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_export_public_key_resp(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len)
+static rpc_status_t serialize_export_public_key_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *data, size_t data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct tlv_iterator resp_iter;
-
- struct tlv_record key_record;
- key_record.tag = TS_CRYPTO_EXPORT_PUBLIC_KEY_OUT_TAG_DATA;
- key_record.length = data_len;
- key_record.value = data;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter;
+ struct tlv_record key_record;
- tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+ key_record.tag = TS_CRYPTO_EXPORT_PUBLIC_KEY_OUT_TAG_DATA;
+ key_record.length = data_length;
+ key_record.value = data;
- if (tlv_encode(&resp_iter, &key_record)) {
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
- resp_buf->data_len = tlv_required_space(data_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (tlv_encode(&resp_iter, &key_record)) {
+ resp_buf->data_length = tlv_required_space(data_length);
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: import_key */
-static rpc_status_t deserialize_import_key_req(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes, uint8_t *data, size_t *data_len)
+static rpc_status_t deserialize_import_key_req(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes, uint8_t *data,
+ size_t *data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_import_key_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_import_key_in);
-
- if (expected_fixed_len <= req_buf->data_len) {
-
- struct tlv_const_iterator req_iter;
- struct tlv_record decoded_record;
-
- rpc_status = TS_RPC_CALL_ACCEPTED;
-
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- packedc_crypto_provider_translate_key_attributes_from_proto(attributes,
- &recv_msg.attributes);
-
- tlv_const_iterator_begin(&req_iter,
- (uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
-
- if (tlv_find_decode(&req_iter, TS_CRYPTO_IMPORT_KEY_IN_TAG_DATA, &decoded_record)) {
-
- if (decoded_record.length <= *data_len) {
-
- memcpy(data, decoded_record.value, decoded_record.length);
- *data_len = decoded_record.length;
- }
- else {
- /* Buffer provided too small */
- return TS_RPC_ERROR_INVALID_REQ_BODY;
- }
- }
- else {
- /* Default for missing parameter */
- *data_len = 0;
- }
- }
-
- return rpc_status;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_import_key_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_import_key_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ struct tlv_const_iterator req_iter;
+ struct tlv_record decoded_record;
+
+ rpc_status = RPC_SUCCESS;
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ packedc_crypto_provider_translate_key_attributes_from_proto(attributes,
+ &recv_msg.attributes);
+
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data + expected_fixed_len,
+ req_buf->data_length - expected_fixed_len);
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_IMPORT_KEY_IN_TAG_DATA, &decoded_record)) {
+ if (decoded_record.length <= *data_length) {
+ memcpy(data, decoded_record.value, decoded_record.length);
+ *data_length = decoded_record.length;
+ } else {
+ /* Buffer provided too small */
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+ }
+ } else {
+ /* Default for missing parameter */
+ *data_length = 0;
+ }
+ }
+
+ return rpc_status;
}
-static rpc_status_t serialize_import_key_resp(struct call_param_buf *resp_buf,
- psa_key_id_t id)
+static rpc_status_t serialize_import_key_resp(struct rpc_buffer *resp_buf, psa_key_id_t id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct ts_crypto_import_key_out resp_msg;
- size_t fixed_len = sizeof(struct ts_crypto_import_key_out);
-
- resp_msg.id = id;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_crypto_import_key_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_crypto_import_key_out);
- if (fixed_len <= resp_buf->size) {
+ resp_msg.id = id;
- memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (fixed_len <= resp_buf->size) {
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: copy_key */
-static rpc_status_t deserialize_copy_key_req(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes,
- psa_key_id_t *source_id)
+static rpc_status_t deserialize_copy_key_req(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes,
+ psa_key_id_t *source_id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_copy_key_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_copy_key_in);
-
- if (expected_fixed_len <= req_buf->data_len) {
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_copy_key_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_copy_key_in);
- rpc_status = TS_RPC_CALL_ACCEPTED;
+ if (expected_fixed_len <= req_buf->data_length) {
+ rpc_status = RPC_SUCCESS;
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- packedc_crypto_provider_translate_key_attributes_from_proto(attributes,
- &recv_msg.attributes);
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ packedc_crypto_provider_translate_key_attributes_from_proto(attributes,
+ &recv_msg.attributes);
- *source_id = recv_msg.source_key_id;
- }
+ *source_id = recv_msg.source_key_id;
+ }
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_copy_key_resp(struct call_param_buf *resp_buf,
- psa_key_id_t target_id)
+static rpc_status_t serialize_copy_key_resp(struct rpc_buffer *resp_buf, psa_key_id_t target_id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct ts_crypto_copy_key_out resp_msg;
- size_t fixed_len = sizeof(struct ts_crypto_copy_key_out);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_crypto_copy_key_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_crypto_copy_key_out);
- resp_msg.target_key_id = target_id;
+ resp_msg.target_key_id = target_id;
- if (fixed_len <= resp_buf->size) {
+ if (fixed_len <= resp_buf->size) {
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
- memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
+ return rpc_status;
}
/* Operation: purge_key */
-static rpc_status_t deserialize_purge_key_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_purge_key_req(const struct rpc_buffer *req_buf, psa_key_id_t *id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_purge_key_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_purge_key_in);
-
- if (expected_fixed_len <= req_buf->data_len) {
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_purge_key_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_purge_key_in);
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- *id = recv_msg.id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (expected_fixed_len <= req_buf->data_length) {
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *id = recv_msg.id;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: get_key_attributes */
-static rpc_status_t deserialize_get_key_attributes_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_get_key_attributes_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_get_key_attributes_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_get_key_attributes_in);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_get_key_attributes_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_get_key_attributes_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *id = recv_msg.id;
+ rpc_status = RPC_SUCCESS;
+ }
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- *id = recv_msg.id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_get_key_attributes_resp(struct call_param_buf *resp_buf,
- const psa_key_attributes_t *attributes)
+static rpc_status_t serialize_get_key_attributes_resp(struct rpc_buffer *resp_buf,
+ const psa_key_attributes_t *attributes)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct ts_crypto_get_key_attributes_out resp_msg;
- size_t fixed_len = sizeof(struct ts_crypto_get_key_attributes_out);
-
- packedc_crypto_provider_translate_key_attributes_to_proto(&resp_msg.attributes, attributes);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_crypto_get_key_attributes_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_crypto_get_key_attributes_out);
- if (fixed_len <= resp_buf->size) {
+ packedc_crypto_provider_translate_key_attributes_to_proto(&resp_msg.attributes, attributes);
- memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (fixed_len <= resp_buf->size) {
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: sign_hash */
-static rpc_status_t deserialize_sign_hash_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *hash, size_t *hash_len)
+static rpc_status_t deserialize_asymmetric_sign_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *hash, size_t *hash_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_sign_hash_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_sign_hash_in);
-
- if (expected_fixed_len <= req_buf->data_len) {
-
- struct tlv_const_iterator req_iter;
- struct tlv_record decoded_record;
-
- rpc_status = TS_RPC_CALL_ACCEPTED;
-
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
-
- *id = recv_msg.id;
- *alg = recv_msg.alg;
-
- tlv_const_iterator_begin(&req_iter,
- (uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
-
- if (tlv_find_decode(&req_iter, TS_CRYPTO_SIGN_HASH_IN_TAG_HASH, &decoded_record)) {
-
- if (decoded_record.length <= *hash_len) {
-
- memcpy(hash, decoded_record.value, decoded_record.length);
- *hash_len = decoded_record.length;
- }
- else {
- /* Buffer provided too small */
- return TS_RPC_ERROR_INVALID_REQ_BODY;
- }
- }
- else {
- /* Default to a zero length hash */
- *hash_len = 0;
- }
- }
-
- return rpc_status;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_sign_hash_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_sign_hash_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ struct tlv_const_iterator req_iter;
+ struct tlv_record decoded_record;
+
+ rpc_status = RPC_SUCCESS;
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+ *id = recv_msg.id;
+ *alg = recv_msg.alg;
+
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data + expected_fixed_len,
+ req_buf->data_length - expected_fixed_len);
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_SIGN_HASH_IN_TAG_HASH, &decoded_record)) {
+ if (decoded_record.length <= *hash_len) {
+ memcpy(hash, decoded_record.value, decoded_record.length);
+ *hash_len = decoded_record.length;
+ } else {
+ /* Buffer provided too small */
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+ }
+ } else {
+ /* Default to a zero length hash */
+ *hash_len = 0;
+ }
+ }
+
+ return rpc_status;
}
-static rpc_status_t serialize_sign_hash_resp(struct call_param_buf *resp_buf,
- const uint8_t *sig, size_t sig_len)
+static rpc_status_t serialize_asymmetric_sign_resp(struct rpc_buffer *resp_buf, const uint8_t *sig,
+ size_t sig_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct tlv_iterator resp_iter;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter;
+ struct tlv_record sig_record;
- struct tlv_record sig_record;
- sig_record.tag = TS_CRYPTO_SIGN_HASH_OUT_TAG_SIGNATURE;
- sig_record.length = sig_len;
- sig_record.value = sig;
+ sig_record.tag = TS_CRYPTO_SIGN_HASH_OUT_TAG_SIGNATURE;
+ sig_record.length = sig_len;
+ sig_record.value = sig;
- tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
- if (tlv_encode(&resp_iter, &sig_record)) {
+ if (tlv_encode(&resp_iter, &sig_record)) {
+ resp_buf->data_length = tlv_required_space(sig_len);
+ rpc_status = RPC_SUCCESS;
+ }
- resp_buf->data_len = tlv_required_space(sig_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
+ return rpc_status;
}
/* Operation: verify_hash */
-static rpc_status_t deserialize_verify_hash_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *hash, size_t *hash_len,
- uint8_t *sig, size_t *sig_len)
+static rpc_status_t deserialize_asymmetric_verify_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *hash, size_t *hash_len, uint8_t *sig,
+ size_t *sig_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_verify_hash_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_verify_hash_in);
-
- if (expected_fixed_len <= req_buf->data_len) {
-
- struct tlv_const_iterator req_iter;
- struct tlv_record decoded_record;
-
- rpc_status = TS_RPC_CALL_ACCEPTED;
-
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
-
- *id = recv_msg.id;
- *alg = recv_msg.alg;
-
- tlv_const_iterator_begin(&req_iter,
- (uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
-
- if (tlv_find_decode(&req_iter, TS_CRYPTO_VERIFY_HASH_IN_TAG_HASH, &decoded_record)) {
-
- if (decoded_record.length <= *hash_len) {
-
- memcpy(hash, decoded_record.value, decoded_record.length);
- *hash_len = decoded_record.length;
- }
- else {
- /* Buffer provided too small */
- return TS_RPC_ERROR_INVALID_REQ_BODY;
- }
- }
- else {
- /* Default to a zero length hash */
- *hash_len = 0;
- }
-
- if (tlv_find_decode(&req_iter, TS_CRYPTO_VERIFY_HASH_IN_TAG_SIGNATURE, &decoded_record)) {
-
- if (decoded_record.length <= *sig_len) {
-
- memcpy(sig, decoded_record.value, decoded_record.length);
- *sig_len = decoded_record.length;
- }
- else {
- /* Buffer provided too small */
- return TS_RPC_ERROR_INVALID_REQ_BODY;
- }
- }
- else {
- /* Default to a zero length hash */
- *sig_len = 0;
- }
- }
-
- return rpc_status;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_verify_hash_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_verify_hash_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ struct tlv_const_iterator req_iter;
+ struct tlv_record decoded_record;
+
+ rpc_status = RPC_SUCCESS;
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+ *id = recv_msg.id;
+ *alg = recv_msg.alg;
+
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data + expected_fixed_len,
+ req_buf->data_length - expected_fixed_len);
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_VERIFY_HASH_IN_TAG_HASH,
+ &decoded_record)) {
+ if (decoded_record.length <= *hash_len) {
+ memcpy(hash, decoded_record.value, decoded_record.length);
+ *hash_len = decoded_record.length;
+ } else {
+ /* Buffer provided too small */
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+ }
+ } else {
+ /* Default to a zero length hash */
+ *hash_len = 0;
+ }
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_VERIFY_HASH_IN_TAG_SIGNATURE,
+ &decoded_record)) {
+ if (decoded_record.length <= *sig_len) {
+ memcpy(sig, decoded_record.value, decoded_record.length);
+ *sig_len = decoded_record.length;
+ } else {
+ /* Buffer provided too small */
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+ }
+ } else {
+ /* Default to a zero length hash */
+ *sig_len = 0;
+ }
+ }
+
+ return rpc_status;
}
/* Operation: asymmetric_decrypt */
-static rpc_status_t deserialize_asymmetric_decrypt_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *ciphertext, size_t *ciphertext_len,
- uint8_t *salt, size_t *salt_len)
+static rpc_status_t deserialize_asymmetric_decrypt_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *ciphertext, size_t *ciphertext_len,
+ uint8_t *salt, size_t *salt_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_asymmetric_decrypt_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_asymmetric_decrypt_in);
-
- if (expected_fixed_len <= req_buf->data_len) {
-
- struct tlv_const_iterator req_iter;
- struct tlv_record decoded_record;
-
- rpc_status = TS_RPC_CALL_ACCEPTED;
-
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
-
- *id = recv_msg.id;
- *alg = recv_msg.alg;
-
- tlv_const_iterator_begin(&req_iter,
- (uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
-
- if (tlv_find_decode(&req_iter, TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_CIPHERTEXT, &decoded_record)) {
-
- if (decoded_record.length <= *ciphertext_len) {
-
- memcpy(ciphertext, decoded_record.value, decoded_record.length);
- *ciphertext_len = decoded_record.length;
- }
- else {
- /* Buffer provided too small */
- return TS_RPC_ERROR_INVALID_REQ_BODY;
- }
- }
- else {
- /* Default to a zero length hash */
- *ciphertext_len = 0;
- }
-
- if (tlv_find_decode(&req_iter, TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_SALT, &decoded_record)) {
-
- if (decoded_record.length <= *salt_len) {
-
- memcpy(salt, decoded_record.value, decoded_record.length);
- *salt_len = decoded_record.length;
- }
- else {
- /* Buffer provided too small */
- return TS_RPC_ERROR_INVALID_REQ_BODY;
- }
- }
- else {
- /* Default to a zero length hash */
- *salt_len = 0;
- }
- }
-
- return rpc_status;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_asymmetric_decrypt_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_asymmetric_decrypt_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ struct tlv_const_iterator req_iter;
+ struct tlv_record decoded_record;
+
+ rpc_status = RPC_SUCCESS;
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+ *id = recv_msg.id;
+ *alg = recv_msg.alg;
+
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data + expected_fixed_len,
+ req_buf->data_length - expected_fixed_len);
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_CIPHERTEXT,
+ &decoded_record)) {
+ if (decoded_record.length <= *ciphertext_len) {
+ memcpy(ciphertext, decoded_record.value, decoded_record.length);
+ *ciphertext_len = decoded_record.length;
+ } else {
+ /* Buffer provided too small */
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+ }
+ } else {
+ /* Default to a zero length hash */
+ *ciphertext_len = 0;
+ }
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_SALT,
+ &decoded_record)) {
+ if (decoded_record.length <= *salt_len) {
+ memcpy(salt, decoded_record.value, decoded_record.length);
+ *salt_len = decoded_record.length;
+ } else {
+ /* Buffer provided too small */
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+ }
+ } else {
+ /* Default to a zero length hash */
+ *salt_len = 0;
+ }
+ }
+
+ return rpc_status;
}
-static rpc_status_t serialize_asymmetric_decrypt_resp(struct call_param_buf *resp_buf,
- const uint8_t *plaintext, size_t plaintext_len)
+static rpc_status_t serialize_asymmetric_decrypt_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *plaintext,
+ size_t plaintext_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct tlv_iterator resp_iter;
-
- struct tlv_record sig_record;
- sig_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_OUT_TAG_PLAINTEXT;
- sig_record.length = plaintext_len;
- sig_record.value = plaintext;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter;
+ struct tlv_record sig_record;
- tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+ sig_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_OUT_TAG_PLAINTEXT;
+ sig_record.length = plaintext_len;
+ sig_record.value = plaintext;
- if (tlv_encode(&resp_iter, &sig_record)) {
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
- resp_buf->data_len = tlv_required_space(plaintext_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (tlv_encode(&resp_iter, &sig_record)) {
+ resp_buf->data_length = tlv_required_space(plaintext_len);
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: asymmetric_encrypt */
-static rpc_status_t deserialize_asymmetric_encrypt_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *plaintext, size_t *plaintext_len,
- uint8_t *salt, size_t *salt_len)
+static rpc_status_t deserialize_asymmetric_encrypt_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *plaintext, size_t *plaintext_len,
+ uint8_t *salt, size_t *salt_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_asymmetric_encrypt_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_asymmetric_encrypt_in);
-
- if (expected_fixed_len <= req_buf->data_len) {
-
- struct tlv_const_iterator req_iter;
- struct tlv_record decoded_record;
-
- rpc_status = TS_RPC_CALL_ACCEPTED;
-
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
-
- *id = recv_msg.id;
- *alg = recv_msg.alg;
-
- tlv_const_iterator_begin(&req_iter,
- (uint8_t*)req_buf->data + expected_fixed_len,
- req_buf->data_len - expected_fixed_len);
-
- if (tlv_find_decode(&req_iter, TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_PLAINTEXT, &decoded_record)) {
-
- if (decoded_record.length <= *plaintext_len) {
-
- memcpy(plaintext, decoded_record.value, decoded_record.length);
- *plaintext_len = decoded_record.length;
- }
- else {
- /* Buffer provided too small */
- return TS_RPC_ERROR_INVALID_REQ_BODY;
- }
- }
- else {
- /* Default to a zero length hash */
- *plaintext_len = 0;
- }
-
- if (tlv_find_decode(&req_iter, TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_SALT, &decoded_record)) {
-
- if (decoded_record.length <= *salt_len) {
-
- memcpy(salt, decoded_record.value, decoded_record.length);
- *salt_len = decoded_record.length;
- }
- else {
- /* Buffer provided too small */
- return TS_RPC_ERROR_INVALID_REQ_BODY;
- }
- }
- else {
- /* Default to a zero length hash */
- *salt_len = 0;
- }
- }
-
- return rpc_status;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_asymmetric_encrypt_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_asymmetric_encrypt_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ struct tlv_const_iterator req_iter;
+ struct tlv_record decoded_record;
+
+ rpc_status = RPC_SUCCESS;
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+ *id = recv_msg.id;
+ *alg = recv_msg.alg;
+
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data + expected_fixed_len,
+ req_buf->data_length - expected_fixed_len);
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_PLAINTEXT,
+ &decoded_record)) {
+ if (decoded_record.length <= *plaintext_len) {
+ memcpy(plaintext, decoded_record.value, decoded_record.length);
+ *plaintext_len = decoded_record.length;
+ } else {
+ /* Buffer provided too small */
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+ }
+ } else {
+ /* Default to a zero length hash */
+ *plaintext_len = 0;
+ }
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_SALT,
+ &decoded_record)) {
+ if (decoded_record.length <= *salt_len) {
+ memcpy(salt, decoded_record.value, decoded_record.length);
+ *salt_len = decoded_record.length;
+ } else {
+ /* Buffer provided too small */
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+ }
+ } else {
+ /* Default to a zero length hash */
+ *salt_len = 0;
+ }
+ }
+
+ return rpc_status;
}
-static rpc_status_t serialize_asymmetric_encrypt_resp(struct call_param_buf *resp_buf,
- const uint8_t *ciphertext, size_t ciphertext_len)
+static rpc_status_t serialize_asymmetric_encrypt_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *ciphertext,
+ size_t ciphertext_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct tlv_iterator resp_iter;
-
- struct tlv_record sig_record;
- sig_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_OUT_TAG_CIPHERTEXT;
- sig_record.length = ciphertext_len;
- sig_record.value = ciphertext;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter;
+ struct tlv_record sig_record;
- tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+ sig_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_OUT_TAG_CIPHERTEXT;
+ sig_record.length = ciphertext_len;
+ sig_record.value = ciphertext;
- if (tlv_encode(&resp_iter, &sig_record)) {
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
- resp_buf->data_len = tlv_required_space(ciphertext_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (tlv_encode(&resp_iter, &sig_record)) {
+ resp_buf->data_length = tlv_required_space(ciphertext_len);
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: generate_random */
-static rpc_status_t deserialize_generate_random_req(const struct call_param_buf *req_buf,
- size_t *size)
+static rpc_status_t deserialize_generate_random_req(const struct rpc_buffer *req_buf, size_t *size)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- struct ts_crypto_generate_random_in recv_msg;
- size_t expected_fixed_len = sizeof(struct ts_crypto_generate_random_in);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ struct ts_crypto_generate_random_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_crypto_generate_random_in);
- if (expected_fixed_len <= req_buf->data_len) {
+ if (expected_fixed_len <= req_buf->data_length) {
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *size = recv_msg.size;
+ rpc_status = RPC_SUCCESS;
+ }
- memcpy(&recv_msg, req_buf->data, expected_fixed_len);
- *size = recv_msg.size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_generate_random_resp(struct call_param_buf *resp_buf,
- const uint8_t *output, size_t output_len)
+static rpc_status_t serialize_generate_random_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *output, size_t output_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct tlv_iterator resp_iter;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter;
+ struct tlv_record out_record;
- struct tlv_record out_record;
- out_record.tag = TS_CRYPTO_GENERATE_RANDOM_OUT_TAG_RANDOM_BYTES;
- out_record.length = output_len;
- out_record.value = output;
+ out_record.tag = TS_CRYPTO_GENERATE_RANDOM_OUT_TAG_RANDOM_BYTES;
+ out_record.length = output_len;
+ out_record.value = output;
- tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
- if (tlv_encode(&resp_iter, &out_record)) {
+ if (tlv_encode(&resp_iter, &out_record)) {
+ resp_buf->data_length = tlv_required_space(output_len);
+ rpc_status = RPC_SUCCESS;
+ }
- resp_buf->data_len = tlv_required_space(output_len);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ return rpc_status;
+}
- return rpc_status;
+/* Operation: mbedtls_verify_pkcs7_signature */
+static rpc_status_t deserialize_verify_pkcs7_signature_req(
+ struct rpc_buffer *req_buf, uint8_t *signature_cert, uint64_t *signature_cert_len,
+ uint8_t *hash, uint64_t *hash_len, uint8_t *public_key_cert, uint64_t *public_key_cert_len)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+
+ if (req_buf->data_length) {
+ struct tlv_const_iterator req_iter;
+ struct tlv_record decoded_record;
+
+ rpc_status = RPC_SUCCESS;
+
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data, req_buf->data_length);
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_SIGNATURE,
+ &decoded_record)) {
+ *signature_cert_len = decoded_record.length;
+
+ if (signature_cert)
+ memcpy(signature_cert, decoded_record.value, decoded_record.length);
+ } else {
+ /* Default to a zero length */
+ *signature_cert_len = 0;
+ }
+
+ if (tlv_find_decode(&req_iter, TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_HASH,
+ &decoded_record)) {
+ *hash_len = decoded_record.length;
+
+ if (hash)
+ memcpy(hash, decoded_record.value, decoded_record.length);
+ } else {
+ /* Default to a zero length */
+ *hash_len = 0;
+ }
+
+ if (tlv_find_decode(&req_iter,
+ TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_PUBLIC_KEY_CERT,
+ &decoded_record)) {
+ *public_key_cert_len = decoded_record.length;
+
+ if (public_key_cert)
+ memcpy(public_key_cert, decoded_record.value,
+ decoded_record.length);
+ } else {
+ /* Default to a zero length */
+ *public_key_cert_len = 0;
+ }
+ }
+
+ return rpc_status;
}
/* Singleton method to provide access to the serializer instance */
const struct crypto_provider_serializer *packedc_crypto_provider_serializer_instance(void)
{
- static const struct crypto_provider_serializer instance = {
- max_deserialised_parameter_size,
- deserialize_generate_key_req,
- serialize_generate_key_resp,
- deserialize_destroy_key_req,
- deserialize_export_key_req,
- serialize_export_key_resp,
- deserialize_export_public_key_req,
- serialize_export_public_key_resp,
- deserialize_import_key_req,
- serialize_import_key_resp,
- deserialize_copy_key_req,
- serialize_copy_key_resp,
- deserialize_purge_key_req,
- deserialize_get_key_attributes_req,
- serialize_get_key_attributes_resp,
- deserialize_sign_hash_req,
- serialize_sign_hash_resp,
- deserialize_verify_hash_req,
- deserialize_asymmetric_decrypt_req,
- serialize_asymmetric_decrypt_resp,
- deserialize_asymmetric_encrypt_req,
- serialize_asymmetric_encrypt_resp,
- deserialize_generate_random_req,
- serialize_generate_random_resp
- };
-
- return &instance;
+ static const struct crypto_provider_serializer instance = {
+ max_deserialised_parameter_size,
+ deserialize_generate_key_req,
+ serialize_generate_key_resp,
+ deserialize_destroy_key_req,
+ deserialize_export_key_req,
+ serialize_export_key_resp,
+ deserialize_export_public_key_req,
+ serialize_export_public_key_resp,
+ deserialize_import_key_req,
+ serialize_import_key_resp,
+ deserialize_copy_key_req,
+ serialize_copy_key_resp,
+ deserialize_purge_key_req,
+ deserialize_get_key_attributes_req,
+ serialize_get_key_attributes_resp,
+ deserialize_asymmetric_sign_req,
+ serialize_asymmetric_sign_resp,
+ deserialize_asymmetric_verify_req,
+ deserialize_asymmetric_decrypt_req,
+ serialize_asymmetric_decrypt_resp,
+ deserialize_asymmetric_encrypt_req,
+ serialize_asymmetric_encrypt_resp,
+ deserialize_generate_random_req,
+ serialize_generate_random_resp,
+ deserialize_verify_pkcs7_signature_req,
+ };
+
+ return &instance;
}
diff --git a/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c b/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c
index 7767d20a1..34cc32651 100644
--- a/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c
+++ b/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c
@@ -1,569 +1,574 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <string.h>
-#include <stdlib.h>
+#include "pb_crypto_provider_serializer.h"
+
+#include <pb_decode.h>
+#include <pb_encode.h>
#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/crypto.h>
#include <service/common/serializer/protobuf/pb_helper.h>
-#include <service/crypto/protobuf/generate_key.pb.h>
+#include <service/crypto/protobuf/asymmetric_decrypt.pb.h>
+#include <service/crypto/protobuf/asymmetric_encrypt.pb.h>
#include <service/crypto/protobuf/destroy_key.pb.h>
#include <service/crypto/protobuf/export_key.pb.h>
#include <service/crypto/protobuf/export_public_key.pb.h>
+#include <service/crypto/protobuf/generate_key.pb.h>
+#include <service/crypto/protobuf/generate_random.pb.h>
#include <service/crypto/protobuf/import_key.pb.h>
#include <service/crypto/protobuf/sign_hash.pb.h>
#include <service/crypto/protobuf/verify_hash.pb.h>
-#include <service/crypto/protobuf/asymmetric_decrypt.pb.h>
-#include <service/crypto/protobuf/asymmetric_encrypt.pb.h>
-#include <service/crypto/protobuf/generate_random.pb.h>
-#include <pb_decode.h>
-#include <pb_encode.h>
-#include <psa/crypto.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "pb_key_attributes_translator.h"
-#include "pb_crypto_provider_serializer.h"
/* Returns the maximum possible deserialized parameter size for a protobuf encoded message. */
-static size_t max_deserialised_parameter_size(const struct call_param_buf *req_buf)
+static size_t max_deserialised_parameter_size(const struct rpc_buffer *req_buf)
{
- /*
- * Assume that a deserialized parameter must be the same size or smaller than the
- * entire serialized message.
- */
- return req_buf->data_len;
+ /*
+ * Assume that a deserialized parameter must be the same size or smaller than the
+ * entire serialized message.
+ */
+ return req_buf->data_length;
}
/* Operation: generate_key */
-static rpc_status_t deserialize_generate_key_req(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes)
+static rpc_status_t deserialize_generate_key_req(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_GenerateKeyIn recv_msg = ts_crypto_GenerateKeyIn_init_default;
-
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_GenerateKeyIn recv_msg = ts_crypto_GenerateKeyIn_init_default;
- if (pb_decode(&istream, ts_crypto_GenerateKeyIn_fields, &recv_msg) && recv_msg.has_attributes) {
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- pb_crypto_provider_translate_key_attributes(attributes, &recv_msg.attributes);
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (pb_decode(&istream, ts_crypto_GenerateKeyIn_fields, &recv_msg) &&
+ recv_msg.has_attributes) {
+ pb_crypto_provider_translate_key_attributes(attributes, &recv_msg.attributes);
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_generate_key_resp(struct call_param_buf *resp_buf,
- psa_key_id_t id)
+static rpc_status_t serialize_generate_key_resp(struct rpc_buffer *resp_buf, psa_key_id_t id)
{
- size_t packed_resp_size;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- ts_crypto_GenerateKeyOut resp_msg = ts_crypto_GenerateKeyOut_init_default;
- resp_msg.id = id;
-
- if (pb_get_encoded_size(&packed_resp_size, ts_crypto_GenerateKeyOut_fields, &resp_msg) &&
- (packed_resp_size <= resp_buf->size)) {
-
- pb_ostream_t ostream = pb_ostream_from_buffer((uint8_t*)resp_buf->data, packed_resp_size);
- if (pb_encode(&ostream, ts_crypto_GenerateKeyOut_fields, &resp_msg)) {
-
- resp_buf->data_len = packed_resp_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
-
- return rpc_status;
+ size_t packed_resp_size;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ ts_crypto_GenerateKeyOut resp_msg = ts_crypto_GenerateKeyOut_init_default;
+ resp_msg.id = id;
+
+ if (pb_get_encoded_size(&packed_resp_size, ts_crypto_GenerateKeyOut_fields, &resp_msg) &&
+ (packed_resp_size <= resp_buf->size)) {
+ pb_ostream_t ostream =
+ pb_ostream_from_buffer((uint8_t *)resp_buf->data, packed_resp_size);
+ if (pb_encode(&ostream, ts_crypto_GenerateKeyOut_fields, &resp_msg)) {
+ resp_buf->data_length = packed_resp_size;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
+
+ return rpc_status;
}
/* Operation: destroy_key */
-static rpc_status_t deserialize_destroy_key_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_destroy_key_req(const struct rpc_buffer *req_buf, psa_key_id_t *id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_DestroyKeyIn recv_msg = ts_crypto_DestroyKeyIn_init_default;
-
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_DestroyKeyIn recv_msg = ts_crypto_DestroyKeyIn_init_default;
- if (pb_decode(&istream, ts_crypto_DestroyKeyIn_fields, &recv_msg)) {
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- *id = recv_msg.id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (pb_decode(&istream, ts_crypto_DestroyKeyIn_fields, &recv_msg)) {
+ *id = recv_msg.id;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
/* Operation: export_key */
-static rpc_status_t deserialize_export_key_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_export_key_req(const struct rpc_buffer *req_buf, psa_key_id_t *id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_ExportKeyIn recv_msg = ts_crypto_ExportKeyIn_init_default;
-
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_ExportKeyIn recv_msg = ts_crypto_ExportKeyIn_init_default;
- if (pb_decode(&istream, ts_crypto_ExportKeyIn_fields, &recv_msg)) {
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- *id = recv_msg.id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (pb_decode(&istream, ts_crypto_ExportKeyIn_fields, &recv_msg)) {
+ *id = recv_msg.id;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_export_key_resp(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len)
+static rpc_status_t serialize_export_key_resp(struct rpc_buffer *resp_buf, const uint8_t *data,
+ size_t data_length)
{
- size_t packed_resp_size;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- ts_crypto_ExportKeyOut resp_msg = ts_crypto_ExportKeyOut_init_default;
- pb_bytes_array_t *key_buffer = pb_malloc_byte_array(data_len);
-
- memcpy(&key_buffer->bytes, data, data_len);
- resp_msg.data = pb_out_byte_array(key_buffer);
-
- if (pb_get_encoded_size(&packed_resp_size, ts_crypto_ExportKeyOut_fields, &resp_msg) &&
- (packed_resp_size <= resp_buf->size)) {
-
- pb_ostream_t ostream = pb_ostream_from_buffer((uint8_t*)resp_buf->data, packed_resp_size);
- if (pb_encode(&ostream, ts_crypto_ExportKeyOut_fields, &resp_msg)) {
-
- resp_buf->data_len = packed_resp_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
-
- free(key_buffer);
-
- return rpc_status;
+ size_t packed_resp_size;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ ts_crypto_ExportKeyOut resp_msg = ts_crypto_ExportKeyOut_init_default;
+ pb_bytes_array_t *key_buffer = pb_malloc_byte_array(data_length);
+
+ memcpy(&key_buffer->bytes, data, data_length);
+ resp_msg.data = pb_out_byte_array(key_buffer);
+
+ if (pb_get_encoded_size(&packed_resp_size, ts_crypto_ExportKeyOut_fields, &resp_msg) &&
+ (packed_resp_size <= resp_buf->size)) {
+ pb_ostream_t ostream =
+ pb_ostream_from_buffer((uint8_t *)resp_buf->data, packed_resp_size);
+ if (pb_encode(&ostream, ts_crypto_ExportKeyOut_fields, &resp_msg)) {
+ resp_buf->data_length = packed_resp_size;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
+
+ free(key_buffer);
+
+ return rpc_status;
}
/* Operation: export_public_key */
-static rpc_status_t deserialize_export_public_key_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_export_public_key_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_ExportPublicKeyIn recv_msg = ts_crypto_ExportPublicKeyIn_init_default;
-
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_ExportPublicKeyIn recv_msg = ts_crypto_ExportPublicKeyIn_init_default;
- if (pb_decode(&istream, ts_crypto_ExportPublicKeyIn_fields, &recv_msg)) {
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- *id = recv_msg.id;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ if (pb_decode(&istream, ts_crypto_ExportPublicKeyIn_fields, &recv_msg)) {
+ *id = recv_msg.id;
+ rpc_status = RPC_SUCCESS;
+ }
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_export_public_key_resp(struct call_param_buf *resp_buf,
- const uint8_t *data, size_t data_len)
+static rpc_status_t serialize_export_public_key_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *data, size_t data_length)
{
- size_t packed_resp_size;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- ts_crypto_ExportPublicKeyOut resp_msg = ts_crypto_ExportPublicKeyOut_init_default;
-
- pb_bytes_array_t *key_buffer = pb_malloc_byte_array(data_len);
- resp_msg.data = pb_out_byte_array(key_buffer);
- memcpy(&key_buffer->bytes, data, data_len);
-
- if (pb_get_encoded_size(&packed_resp_size, ts_crypto_ExportPublicKeyOut_fields, &resp_msg) &&
- (packed_resp_size <= resp_buf->size)) {
-
- pb_ostream_t ostream = pb_ostream_from_buffer((uint8_t*)resp_buf->data, packed_resp_size);
- if (pb_encode(&ostream, ts_crypto_ExportPublicKeyOut_fields, &resp_msg)) {
-
- resp_buf->data_len = packed_resp_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
-
- free(key_buffer);
-
- return rpc_status;
+ size_t packed_resp_size;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ ts_crypto_ExportPublicKeyOut resp_msg = ts_crypto_ExportPublicKeyOut_init_default;
+
+ pb_bytes_array_t *key_buffer = pb_malloc_byte_array(data_length);
+ resp_msg.data = pb_out_byte_array(key_buffer);
+ memcpy(&key_buffer->bytes, data, data_length);
+
+ if (pb_get_encoded_size(&packed_resp_size, ts_crypto_ExportPublicKeyOut_fields,
+ &resp_msg) &&
+ (packed_resp_size <= resp_buf->size)) {
+ pb_ostream_t ostream =
+ pb_ostream_from_buffer((uint8_t *)resp_buf->data, packed_resp_size);
+ if (pb_encode(&ostream, ts_crypto_ExportPublicKeyOut_fields, &resp_msg)) {
+ resp_buf->data_length = packed_resp_size;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
+
+ free(key_buffer);
+
+ return rpc_status;
}
/* Operation: import_key */
-static rpc_status_t deserialize_import_key_req(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes, uint8_t *data, size_t *data_len)
+static rpc_status_t deserialize_import_key_req(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes, uint8_t *data,
+ size_t *data_length)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_ImportKeyIn recv_msg = ts_crypto_ImportKeyIn_init_default;
-
- pb_bytes_array_t *key_buffer = pb_malloc_byte_array(*data_len);
- recv_msg.data = pb_in_byte_array(key_buffer);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_ImportKeyIn recv_msg = ts_crypto_ImportKeyIn_init_default;
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ pb_bytes_array_t *key_buffer = pb_malloc_byte_array(*data_length);
+ recv_msg.data = pb_in_byte_array(key_buffer);
- if (pb_decode(&istream, ts_crypto_ImportKeyIn_fields, &recv_msg) &&
- recv_msg.has_attributes &&
- (key_buffer->size <= *data_len)) {
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- pb_crypto_provider_translate_key_attributes(attributes, &recv_msg.attributes);
+ if (pb_decode(&istream, ts_crypto_ImportKeyIn_fields, &recv_msg) &&
+ recv_msg.has_attributes && (key_buffer->size <= *data_length)) {
+ pb_crypto_provider_translate_key_attributes(attributes, &recv_msg.attributes);
- memcpy(data, &key_buffer->bytes, key_buffer->size);
- *data_len = key_buffer->size;
+ memcpy(data, &key_buffer->bytes, key_buffer->size);
+ *data_length = key_buffer->size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ rpc_status = RPC_SUCCESS;
+ }
- free(key_buffer);
+ free(key_buffer);
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_import_key_resp(struct call_param_buf *resp_buf,
- psa_key_id_t id)
+static rpc_status_t serialize_import_key_resp(struct rpc_buffer *resp_buf, psa_key_id_t id)
{
- size_t packed_resp_size;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- ts_crypto_ImportKeyOut resp_msg = ts_crypto_ImportKeyOut_init_default;
- resp_msg.id = id;
-
- if (pb_get_encoded_size(&packed_resp_size, ts_crypto_ImportKeyOut_fields, &resp_msg) &&
- (packed_resp_size <= resp_buf->size)) {
-
- pb_ostream_t ostream = pb_ostream_from_buffer((uint8_t*)resp_buf->data, packed_resp_size);
- if (pb_encode(&ostream, ts_crypto_ImportKeyOut_fields, &resp_msg)) {
-
- resp_buf->data_len = packed_resp_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
-
- return rpc_status;
+ size_t packed_resp_size;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ ts_crypto_ImportKeyOut resp_msg = ts_crypto_ImportKeyOut_init_default;
+ resp_msg.id = id;
+
+ if (pb_get_encoded_size(&packed_resp_size, ts_crypto_ImportKeyOut_fields, &resp_msg) &&
+ (packed_resp_size <= resp_buf->size)) {
+ pb_ostream_t ostream =
+ pb_ostream_from_buffer((uint8_t *)resp_buf->data, packed_resp_size);
+ if (pb_encode(&ostream, ts_crypto_ImportKeyOut_fields, &resp_msg)) {
+ resp_buf->data_length = packed_resp_size;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
+
+ return rpc_status;
}
/* Operation: copy_key */
-static rpc_status_t deserialize_copy_key_req(const struct call_param_buf *req_buf,
- psa_key_attributes_t *attributes,
- psa_key_id_t *source_id)
+static rpc_status_t deserialize_copy_key_req(const struct rpc_buffer *req_buf,
+ psa_key_attributes_t *attributes,
+ psa_key_id_t *source_id)
{
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ (void)req_buf;
+ (void)attributes;
+ (void)source_id;
+
+ return RPC_ERROR_INVALID_REQUEST_BODY;
}
-static rpc_status_t serialize_copy_key_resp(struct call_param_buf *resp_buf,
- psa_key_id_t target_id)
+static rpc_status_t serialize_copy_key_resp(struct rpc_buffer *resp_buf, psa_key_id_t target_id)
{
- return TS_RPC_ERROR_INTERNAL;
+ (void)resp_buf;
+ (void)target_id;
+
+ return RPC_ERROR_INTERNAL;
}
/* Operation: purge_key */
-static rpc_status_t deserialize_purge_key_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_purge_key_req(const struct rpc_buffer *req_buf, psa_key_id_t *id)
{
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ (void)req_buf;
+ (void)id;
+
+ return RPC_ERROR_INVALID_REQUEST_BODY;
}
/* Operation: get_key_attributes */
-static rpc_status_t deserialize_get_key_attributes_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id)
+static rpc_status_t deserialize_get_key_attributes_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id)
{
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ (void)req_buf;
+ (void)id;
+
+ return RPC_ERROR_INVALID_REQUEST_BODY;
}
-static rpc_status_t serialize_get_key_attributes_resp(struct call_param_buf *resp_buf,
- const psa_key_attributes_t *attributes)
+static rpc_status_t serialize_get_key_attributes_resp(struct rpc_buffer *resp_buf,
+ const psa_key_attributes_t *attributes)
{
- return TS_RPC_ERROR_INTERNAL;
+ (void)resp_buf;
+ (void)attributes;
+
+ return RPC_ERROR_INTERNAL;
}
/* Operation: sign_hash */
-static rpc_status_t deserialize_sign_hash_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *hash, size_t *hash_len)
+static rpc_status_t deserialize_asymmetric_sign_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *hash, size_t *hash_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_SignHashIn recv_msg = ts_crypto_SignHashIn_init_default;
-
- pb_bytes_array_t *hash_buffer = pb_malloc_byte_array(*hash_len);
- recv_msg.hash = pb_in_byte_array(hash_buffer);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_SignHashIn recv_msg = ts_crypto_SignHashIn_init_default;
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ pb_bytes_array_t *hash_buffer = pb_malloc_byte_array(*hash_len);
+ recv_msg.hash = pb_in_byte_array(hash_buffer);
- if (pb_decode(&istream, ts_crypto_SignHashIn_fields, &recv_msg)) {
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- *id = recv_msg.id;
- *alg = recv_msg.alg;
+ if (pb_decode(&istream, ts_crypto_SignHashIn_fields, &recv_msg)) {
+ *id = recv_msg.id;
+ *alg = recv_msg.alg;
- memcpy(hash, &hash_buffer->bytes, hash_buffer->size);
- *hash_len = hash_buffer->size;
+ memcpy(hash, &hash_buffer->bytes, hash_buffer->size);
+ *hash_len = hash_buffer->size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ rpc_status = RPC_SUCCESS;
+ }
- free(hash_buffer);
+ free(hash_buffer);
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_sign_hash_resp(struct call_param_buf *resp_buf,
- const uint8_t *sig, size_t sig_len)
+static rpc_status_t serialize_asymmetric_sign_resp(struct rpc_buffer *resp_buf, const uint8_t *sig,
+ size_t sig_len)
{
- size_t packed_resp_size;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- ts_crypto_SignHashOut resp_msg = ts_crypto_SignHashOut_init_default;
-
- pb_bytes_array_t *sig_buffer = pb_malloc_byte_array(sig_len);
- resp_msg.signature = pb_out_byte_array(sig_buffer);
- memcpy(&sig_buffer->bytes, sig, sig_len);
-
- if (pb_get_encoded_size(&packed_resp_size, ts_crypto_SignHashOut_fields, &resp_msg) &&
- (packed_resp_size <= resp_buf->size)) {
-
- pb_ostream_t ostream = pb_ostream_from_buffer((uint8_t*)resp_buf->data, packed_resp_size);
- if (pb_encode(&ostream, ts_crypto_SignHashOut_fields, &resp_msg)) {
-
- resp_buf->data_len = packed_resp_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
-
- free(sig_buffer);
-
- return rpc_status;
+ size_t packed_resp_size;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ ts_crypto_SignHashOut resp_msg = ts_crypto_SignHashOut_init_default;
+
+ pb_bytes_array_t *sig_buffer = pb_malloc_byte_array(sig_len);
+ resp_msg.signature = pb_out_byte_array(sig_buffer);
+ memcpy(&sig_buffer->bytes, sig, sig_len);
+
+ if (pb_get_encoded_size(&packed_resp_size, ts_crypto_SignHashOut_fields, &resp_msg) &&
+ (packed_resp_size <= resp_buf->size)) {
+ pb_ostream_t ostream =
+ pb_ostream_from_buffer((uint8_t *)resp_buf->data, packed_resp_size);
+ if (pb_encode(&ostream, ts_crypto_SignHashOut_fields, &resp_msg)) {
+ resp_buf->data_length = packed_resp_size;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
+
+ free(sig_buffer);
+
+ return rpc_status;
}
/* Operation: verify_hash */
-static rpc_status_t deserialize_verify_hash_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *hash, size_t *hash_len,
- uint8_t *sig, size_t *sig_len)
+static rpc_status_t deserialize_asymmetric_verify_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *hash, size_t *hash_len, uint8_t *sig,
+ size_t *sig_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_VerifyHashIn recv_msg = ts_crypto_VerifyHashIn_init_default;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_VerifyHashIn recv_msg = ts_crypto_VerifyHashIn_init_default;
- pb_bytes_array_t *hash_buffer = pb_malloc_byte_array(*hash_len);
- recv_msg.hash = pb_in_byte_array(hash_buffer);
+ pb_bytes_array_t *hash_buffer = pb_malloc_byte_array(*hash_len);
+ recv_msg.hash = pb_in_byte_array(hash_buffer);
- pb_bytes_array_t *sig_buffer = pb_malloc_byte_array(*sig_len);
- recv_msg.signature = pb_in_byte_array(sig_buffer);
+ pb_bytes_array_t *sig_buffer = pb_malloc_byte_array(*sig_len);
+ recv_msg.signature = pb_in_byte_array(sig_buffer);
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- if (pb_decode(&istream, ts_crypto_VerifyHashIn_fields, &recv_msg)) {
+ if (pb_decode(&istream, ts_crypto_VerifyHashIn_fields, &recv_msg)) {
+ *id = recv_msg.id;
+ *alg = recv_msg.alg;
- *id = recv_msg.id;
- *alg = recv_msg.alg;
+ memcpy(hash, &hash_buffer->bytes, hash_buffer->size);
+ *hash_len = hash_buffer->size;
- memcpy(hash, &hash_buffer->bytes, hash_buffer->size);
- *hash_len = hash_buffer->size;
+ memcpy(sig, &sig_buffer->bytes, sig_buffer->size);
+ *sig_len = sig_buffer->size;
- memcpy(sig, &sig_buffer->bytes, sig_buffer->size);
- *sig_len = sig_buffer->size;
+ rpc_status = RPC_SUCCESS;
+ }
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ free(hash_buffer);
+ free(sig_buffer);
- free(hash_buffer);
- free(sig_buffer);
-
- return rpc_status;
+ return rpc_status;
}
/* Operation: asymmetric_decrypt */
-static rpc_status_t deserialize_asymmetric_decrypt_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *ciphertext, size_t *ciphertext_len,
- uint8_t *salt, size_t *salt_len)
+static rpc_status_t deserialize_asymmetric_decrypt_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *ciphertext, size_t *ciphertext_len,
+ uint8_t *salt, size_t *salt_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_AsymmetricDecryptIn recv_msg = ts_crypto_AsymmetricDecryptIn_init_default;
-
- pb_bytes_array_t *ciphertext_buffer = pb_malloc_byte_array(*ciphertext_len);
- recv_msg.ciphertext = pb_in_byte_array(ciphertext_buffer);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_AsymmetricDecryptIn recv_msg = ts_crypto_AsymmetricDecryptIn_init_default;
- pb_bytes_array_t *salt_buffer = pb_malloc_byte_array(*salt_len);
- recv_msg.salt = pb_in_byte_array(salt_buffer);
- *salt_len = 0; /* Default for optional parameter */
+ pb_bytes_array_t *ciphertext_buffer = pb_malloc_byte_array(*ciphertext_len);
+ recv_msg.ciphertext = pb_in_byte_array(ciphertext_buffer);
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ pb_bytes_array_t *salt_buffer = pb_malloc_byte_array(*salt_len);
+ recv_msg.salt = pb_in_byte_array(salt_buffer);
- if (pb_decode(&istream, ts_crypto_AsymmetricDecryptIn_fields, &recv_msg)) {
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- *id = recv_msg.id;
- *alg = recv_msg.alg;
+ if (pb_decode(&istream, ts_crypto_AsymmetricDecryptIn_fields, &recv_msg)) {
+ *id = recv_msg.id;
+ *alg = recv_msg.alg;
- memcpy(ciphertext, &ciphertext_buffer->bytes, ciphertext_buffer->size);
- *ciphertext_len = ciphertext_buffer->size;
+ memcpy(ciphertext, &ciphertext_buffer->bytes, ciphertext_buffer->size);
+ *ciphertext_len = ciphertext_buffer->size;
- memcpy(salt, &salt_buffer->bytes, salt_buffer->size);
- *salt_len = salt_buffer->size;
+ if (salt_buffer->size < *salt_len) {
+ memcpy(salt, &salt_buffer->bytes, salt_buffer->size);
+ *salt_len = salt_buffer->size;
+ } else {
+ /* Set default for missing optional parameter */
+ *salt_len = 0;
+ }
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ rpc_status = RPC_SUCCESS;
+ }
- free(ciphertext_buffer);
- free(salt_buffer);
+ free(ciphertext_buffer);
+ free(salt_buffer);
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_asymmetric_decrypt_resp(struct call_param_buf *resp_buf,
- const uint8_t *plaintext, size_t plaintext_len)
+static rpc_status_t serialize_asymmetric_decrypt_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *plaintext,
+ size_t plaintext_len)
{
- size_t packed_resp_size;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- ts_crypto_AsymmetricDecryptOut resp_msg = ts_crypto_AsymmetricDecryptOut_init_default;
-
- pb_bytes_array_t *plaintext_buffer = pb_malloc_byte_array(plaintext_len);
- resp_msg.plaintext = pb_out_byte_array(plaintext_buffer);
- memcpy(&plaintext_buffer->bytes, plaintext, plaintext_len);
-
- if (pb_get_encoded_size(&packed_resp_size, ts_crypto_AsymmetricDecryptOut_fields, &resp_msg) &&
- (packed_resp_size <= resp_buf->size)) {
-
- pb_ostream_t ostream = pb_ostream_from_buffer((uint8_t*)resp_buf->data, packed_resp_size);
- if (pb_encode(&ostream, ts_crypto_AsymmetricDecryptOut_fields, &resp_msg)) {
-
- resp_buf->data_len = packed_resp_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
-
- free(plaintext_buffer);
-
- return rpc_status;
+ size_t packed_resp_size;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ ts_crypto_AsymmetricDecryptOut resp_msg = ts_crypto_AsymmetricDecryptOut_init_default;
+
+ pb_bytes_array_t *plaintext_buffer = pb_malloc_byte_array(plaintext_len);
+ resp_msg.plaintext = pb_out_byte_array(plaintext_buffer);
+ memcpy(&plaintext_buffer->bytes, plaintext, plaintext_len);
+
+ if (pb_get_encoded_size(&packed_resp_size, ts_crypto_AsymmetricDecryptOut_fields,
+ &resp_msg) &&
+ (packed_resp_size <= resp_buf->size)) {
+ pb_ostream_t ostream =
+ pb_ostream_from_buffer((uint8_t *)resp_buf->data, packed_resp_size);
+ if (pb_encode(&ostream, ts_crypto_AsymmetricDecryptOut_fields, &resp_msg)) {
+ resp_buf->data_length = packed_resp_size;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
+
+ free(plaintext_buffer);
+
+ return rpc_status;
}
/* Operation: asymmetric_encrypt */
-static rpc_status_t deserialize_asymmetric_encrypt_req(const struct call_param_buf *req_buf,
- psa_key_id_t *id, psa_algorithm_t *alg,
- uint8_t *plaintext, size_t *plaintext_len,
- uint8_t *salt, size_t *salt_len)
+static rpc_status_t deserialize_asymmetric_encrypt_req(const struct rpc_buffer *req_buf,
+ psa_key_id_t *id, psa_algorithm_t *alg,
+ uint8_t *plaintext, size_t *plaintext_len,
+ uint8_t *salt, size_t *salt_len)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_AsymmetricEncryptIn recv_msg = ts_crypto_AsymmetricEncryptIn_init_default;
-
- pb_bytes_array_t *plaintext_buffer = pb_malloc_byte_array(*plaintext_len);
- recv_msg.plaintext = pb_in_byte_array(plaintext_buffer);
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_AsymmetricEncryptIn recv_msg = ts_crypto_AsymmetricEncryptIn_init_default;
- pb_bytes_array_t *salt_buffer = pb_malloc_byte_array(*salt_len);
- recv_msg.salt = pb_in_byte_array(salt_buffer);
- *salt_len = 0; /* Default for optional parameter */
+ pb_bytes_array_t *plaintext_buffer = pb_malloc_byte_array(*plaintext_len);
+ recv_msg.plaintext = pb_in_byte_array(plaintext_buffer);
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ pb_bytes_array_t *salt_buffer = pb_malloc_byte_array(*salt_len);
+ recv_msg.salt = pb_in_byte_array(salt_buffer);
- if (pb_decode(&istream, ts_crypto_AsymmetricEncryptIn_fields, &recv_msg)) {
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- *id = recv_msg.id;
- *alg = recv_msg.alg;
+ if (pb_decode(&istream, ts_crypto_AsymmetricEncryptIn_fields, &recv_msg)) {
+ *id = recv_msg.id;
+ *alg = recv_msg.alg;
- memcpy(plaintext, &plaintext_buffer->bytes, plaintext_buffer->size);
- *plaintext_len = plaintext_buffer->size;
+ memcpy(plaintext, &plaintext_buffer->bytes, plaintext_buffer->size);
+ *plaintext_len = plaintext_buffer->size;
- memcpy(salt, &salt_buffer->bytes, salt_buffer->size);
- *salt_len = salt_buffer->size;
+ if (salt_buffer->size < *salt_len) {
+ memcpy(salt, &salt_buffer->bytes, salt_buffer->size);
+ *salt_len = salt_buffer->size;
+ } else {
+ /* Set default for missing optional parameter */
+ *salt_len = 0;
+ }
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
+ rpc_status = RPC_SUCCESS;
+ }
- free(plaintext_buffer);
- free(salt_buffer);
+ free(plaintext_buffer);
+ free(salt_buffer);
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_asymmetric_encrypt_resp(struct call_param_buf *resp_buf,
- const uint8_t *ciphertext, size_t ciphertext_len)
+static rpc_status_t serialize_asymmetric_encrypt_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *ciphertext,
+ size_t ciphertext_len)
{
- size_t packed_resp_size;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- ts_crypto_AsymmetricEncryptOut resp_msg = ts_crypto_AsymmetricEncryptOut_init_default;
-
- pb_bytes_array_t *ciphertext_buffer = pb_malloc_byte_array(ciphertext_len);
- resp_msg.ciphertext = pb_out_byte_array(ciphertext_buffer);
- memcpy(&ciphertext_buffer->bytes, ciphertext, ciphertext_len);
-
- if (pb_get_encoded_size(&packed_resp_size, ts_crypto_AsymmetricEncryptOut_fields, &resp_msg) &&
- (packed_resp_size <= resp_buf->size)) {
-
- pb_ostream_t ostream = pb_ostream_from_buffer((uint8_t*)resp_buf->data, packed_resp_size);
- if (pb_encode(&ostream, ts_crypto_AsymmetricEncryptOut_fields, &resp_msg)) {
-
- resp_buf->data_len = packed_resp_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
-
- free(ciphertext_buffer);
-
- return rpc_status;
+ size_t packed_resp_size;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ ts_crypto_AsymmetricEncryptOut resp_msg = ts_crypto_AsymmetricEncryptOut_init_default;
+
+ pb_bytes_array_t *ciphertext_buffer = pb_malloc_byte_array(ciphertext_len);
+ resp_msg.ciphertext = pb_out_byte_array(ciphertext_buffer);
+ memcpy(&ciphertext_buffer->bytes, ciphertext, ciphertext_len);
+
+ if (pb_get_encoded_size(&packed_resp_size, ts_crypto_AsymmetricEncryptOut_fields,
+ &resp_msg) &&
+ (packed_resp_size <= resp_buf->size)) {
+ pb_ostream_t ostream =
+ pb_ostream_from_buffer((uint8_t *)resp_buf->data, packed_resp_size);
+ if (pb_encode(&ostream, ts_crypto_AsymmetricEncryptOut_fields, &resp_msg)) {
+ resp_buf->data_length = packed_resp_size;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
+
+ free(ciphertext_buffer);
+
+ return rpc_status;
}
/* Operation: generate_random */
-static rpc_status_t deserialize_generate_random_req(const struct call_param_buf *req_buf,
- size_t *size)
+static rpc_status_t deserialize_generate_random_req(const struct rpc_buffer *req_buf, size_t *size)
{
- rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
- ts_crypto_GenerateRandomIn recv_msg = ts_crypto_GenerateRandomIn_init_default;
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ ts_crypto_GenerateRandomIn recv_msg = ts_crypto_GenerateRandomIn_init_default;
- pb_istream_t istream = pb_istream_from_buffer((const uint8_t*)req_buf->data, req_buf->data_len);
+ pb_istream_t istream =
+ pb_istream_from_buffer((const uint8_t *)req_buf->data, req_buf->data_length);
- if (pb_decode(&istream, ts_crypto_GenerateRandomIn_fields, &recv_msg)) {
+ if (pb_decode(&istream, ts_crypto_GenerateRandomIn_fields, &recv_msg)) {
+ *size = recv_msg.size;
- *size = recv_msg.size;
+ rpc_status = RPC_SUCCESS;
+ }
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t serialize_generate_random_resp(struct call_param_buf *resp_buf,
- const uint8_t *output, size_t output_len)
+static rpc_status_t serialize_generate_random_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *output, size_t output_len)
{
- size_t packed_resp_size;
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- ts_crypto_GenerateRandomOut resp_msg = ts_crypto_GenerateRandomOut_init_default;
-
- pb_bytes_array_t *output_buffer = pb_malloc_byte_array(output_len);
- resp_msg.random_bytes = pb_out_byte_array(output_buffer);
- memcpy(&output_buffer->bytes, output, output_len);
-
- if (pb_get_encoded_size(&packed_resp_size, ts_crypto_GenerateRandomOut_fields, &resp_msg) &&
- (packed_resp_size <= resp_buf->size)) {
-
- pb_ostream_t ostream = pb_ostream_from_buffer((uint8_t*)resp_buf->data, packed_resp_size);
- if (pb_encode(&ostream, ts_crypto_GenerateRandomOut_fields, &resp_msg)) {
-
- resp_buf->data_len = packed_resp_size;
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
- }
-
- free(output_buffer);
-
- return rpc_status;
+ size_t packed_resp_size;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ ts_crypto_GenerateRandomOut resp_msg = ts_crypto_GenerateRandomOut_init_default;
+
+ pb_bytes_array_t *output_buffer = pb_malloc_byte_array(output_len);
+ resp_msg.random_bytes = pb_out_byte_array(output_buffer);
+ memcpy(&output_buffer->bytes, output, output_len);
+
+ if (pb_get_encoded_size(&packed_resp_size, ts_crypto_GenerateRandomOut_fields, &resp_msg) &&
+ (packed_resp_size <= resp_buf->size)) {
+ pb_ostream_t ostream =
+ pb_ostream_from_buffer((uint8_t *)resp_buf->data, packed_resp_size);
+ if (pb_encode(&ostream, ts_crypto_GenerateRandomOut_fields, &resp_msg)) {
+ resp_buf->data_length = packed_resp_size;
+ rpc_status = RPC_SUCCESS;
+ }
+ }
+
+ free(output_buffer);
+
+ return rpc_status;
}
/* Singleton method to provide access to the serializer instance */
const struct crypto_provider_serializer *pb_crypto_provider_serializer_instance(void)
{
- static const struct crypto_provider_serializer instance = {
- max_deserialised_parameter_size,
- deserialize_generate_key_req,
- serialize_generate_key_resp,
- deserialize_destroy_key_req,
- deserialize_export_key_req,
- serialize_export_key_resp,
- deserialize_export_public_key_req,
- serialize_export_public_key_resp,
- deserialize_import_key_req,
- serialize_import_key_resp,
- deserialize_copy_key_req,
- serialize_copy_key_resp,
- deserialize_purge_key_req,
- deserialize_get_key_attributes_req,
- serialize_get_key_attributes_resp,
- deserialize_sign_hash_req,
- serialize_sign_hash_resp,
- deserialize_verify_hash_req,
- deserialize_asymmetric_decrypt_req,
- serialize_asymmetric_decrypt_resp,
- deserialize_asymmetric_encrypt_req,
- serialize_asymmetric_encrypt_resp,
- deserialize_generate_random_req,
- serialize_generate_random_resp
- };
-
- return &instance;
+ static const struct crypto_provider_serializer instance = {
+ max_deserialised_parameter_size, deserialize_generate_key_req,
+ serialize_generate_key_resp, deserialize_destroy_key_req,
+ deserialize_export_key_req, serialize_export_key_resp,
+ deserialize_export_public_key_req, serialize_export_public_key_resp,
+ deserialize_import_key_req, serialize_import_key_resp,
+ deserialize_copy_key_req, serialize_copy_key_resp,
+ deserialize_purge_key_req, deserialize_get_key_attributes_req,
+ serialize_get_key_attributes_resp, deserialize_asymmetric_sign_req,
+ serialize_asymmetric_sign_resp, deserialize_asymmetric_verify_req,
+ deserialize_asymmetric_decrypt_req, serialize_asymmetric_decrypt_resp,
+ deserialize_asymmetric_encrypt_req, serialize_asymmetric_encrypt_resp,
+ deserialize_generate_random_req, serialize_generate_random_resp
+ };
+
+ return &instance;
}
diff --git a/components/service/crypto/test/protocol/check_crypto_opcode_alignment.cpp b/components/service/crypto/test/protocol/check_crypto_opcode_alignment.cpp
index bd6c66ee5..da01abf4e 100644
--- a/components/service/crypto/test/protocol/check_crypto_opcode_alignment.cpp
+++ b/components/service/crypto/test/protocol/check_crypto_opcode_alignment.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,15 +18,16 @@ TEST_GROUP(CryptoProtocolOpcodeChecks)
TEST(CryptoProtocolOpcodeChecks, checkPackedcToProtobuf)
{
- CHECK_EQUAL(TS_CRYPTO_OPCODE_GENERATE_KEY, ts_crypto_Opcode_GENERATE_KEY);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_DESTROY_KEY, ts_crypto_Opcode_DESTROY_KEY);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_EXPORT_KEY, ts_crypto_Opcode_EXPORT_KEY);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, ts_crypto_Opcode_EXPORT_PUBLIC_KEY);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_IMPORT_KEY, ts_crypto_Opcode_IMPORT_KEY);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_SIGN_HASH, ts_crypto_Opcode_SIGN_HASH);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_VERIFY_HASH, ts_crypto_Opcode_VERIFY_HASH);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, ts_crypto_Opcode_ASYMMETRIC_DECRYPT);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, ts_crypto_Opcode_ASYMMETRIC_ENCRYPT);
- CHECK_EQUAL(TS_CRYPTO_OPCODE_GENERATE_RANDOM, ts_crypto_Opcode_GENERATE_RANDOM);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_GENERATE_KEY, ts_crypto_Opcode_GENERATE_KEY);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_DESTROY_KEY, ts_crypto_Opcode_DESTROY_KEY);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_EXPORT_KEY, ts_crypto_Opcode_EXPORT_KEY);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, ts_crypto_Opcode_EXPORT_PUBLIC_KEY);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_IMPORT_KEY, ts_crypto_Opcode_IMPORT_KEY);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_SIGN_HASH, ts_crypto_Opcode_SIGN_HASH);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_VERIFY_HASH, ts_crypto_Opcode_VERIFY_HASH);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, ts_crypto_Opcode_ASYMMETRIC_DECRYPT);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, ts_crypto_Opcode_ASYMMETRIC_ENCRYPT);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_GENERATE_RANDOM, ts_crypto_Opcode_GENERATE_RANDOM);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_SIGN_MESSAGE, ts_crypto_Opcode_SIGN_MESSAGE);
+ CHECK_EQUAL(TS_CRYPTO_OPCODE_VERIFY_MESSAGE, ts_crypto_Opcode_VERIFY_MESSAGE);
}
-
diff --git a/components/service/crypto/test/service/crypto_service_limit_tests.cpp b/components/service/crypto/test/service/crypto_service_limit_tests.cpp
index c539b4325..294b87473 100644
--- a/components/service/crypto/test/service/crypto_service_limit_tests.cpp
+++ b/components/service/crypto/test/service/crypto_service_limit_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,9 +8,8 @@
#include <vector>
#include <cstring>
#include <cstdint>
-#include <service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h>
-#include <protocols/rpc/common/packed-c/encoding.h>
-#include <service_locator.h>
+#include <service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h>
+#include <service/locator/interface/service_locator.h>
#include <CppUTest/TestHarness.h>
/*
@@ -21,22 +20,16 @@ TEST_GROUP(CryptoServiceLimitTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
- m_crypto_service_context = NULL;
- m_crypto_client = NULL;
-
service_locator_init();
- m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
- CHECK(m_crypto_service_context);
+ m_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0");
+ CHECK_TRUE(m_service_context != NULL);
- m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PROTOBUF, &caller);
- CHECK(m_rpc_session_handle);
+ m_session = service_context_open(m_service_context);
+ CHECK_TRUE(m_session != NULL);
- m_crypto_client = new protobuf_crypto_client(caller);
+ m_crypto_client = new packedc_crypto_client(m_session);
+ CHECK(m_crypto_client != NULL);
}
void teardown()
@@ -44,11 +37,15 @@ TEST_GROUP(CryptoServiceLimitTests)
delete m_crypto_client;
m_crypto_client = NULL;
- service_context_close(m_crypto_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_session) {
+ service_context_close(m_service_context, m_session);
+ m_session = NULL;
+ }
- service_context_relinquish(m_crypto_service_context);
- m_crypto_service_context = NULL;
+ if (m_service_context) {
+ service_context_relinquish(m_service_context);
+ m_service_context = NULL;
+ }
}
psa_status_t generateVolatileEccKeyPair(std::vector<psa_key_id_t> &key_ids)
@@ -81,7 +78,7 @@ TEST_GROUP(CryptoServiceLimitTests)
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
- psa_set_key_bits(&attributes, 512);
+ psa_set_key_bits(&attributes, 1024);
psa_key_id_t key_id;
status = m_crypto_client->generate_key(&attributes, &key_id);
@@ -114,8 +111,8 @@ TEST_GROUP(CryptoServiceLimitTests)
*/
const size_t MAX_KEY_SLOTS = 30;
- rpc_session_handle m_rpc_session_handle;
- struct service_context *m_crypto_service_context;
+ struct service_context *m_service_context;
+ struct rpc_caller_session *m_session;
crypto_client *m_crypto_client;
};
diff --git a/components/service/crypto/test/service/crypto_service_scenarios.cpp b/components/service/crypto/test/service/crypto_service_scenarios.cpp
index ec2c6736a..db7d69175 100644
--- a/components/service/crypto/test/service/crypto_service_scenarios.cpp
+++ b/components/service/crypto/test/service/crypto_service_scenarios.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -104,7 +104,7 @@ void crypto_service_scenarios::copyKey()
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_COPY);
psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
- psa_set_key_bits(&attributes, 256);
+ psa_set_key_bits(&attributes, 1024);
/* Generate a key */
psa_key_id_t key_id_1;
@@ -290,6 +290,56 @@ void crypto_service_scenarios::signAndVerifyHash()
CHECK_EQUAL(PSA_SUCCESS, status);
}
+void crypto_service_scenarios::signAndVerifyMessage()
+{
+ psa_status_t status;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_key_id_t key_id;
+
+ psa_set_key_id(&attributes, 14);
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE);
+ psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+ psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+ psa_set_key_bits(&attributes, 256);
+
+ /* Generate a key */
+ status = m_crypto_client->generate_key(&attributes, &key_id);
+ CHECK_EQUAL(PSA_SUCCESS, status);
+
+ psa_reset_key_attributes(&attributes);
+
+ /* Sign a message */
+ uint8_t message[21];
+ uint8_t signature[PSA_SIGNATURE_MAX_SIZE];
+ size_t signature_length;
+
+ memset(message, 0x99, sizeof(message));
+
+ status = m_crypto_client->sign_message(key_id,
+ PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), message, sizeof(message),
+ signature, sizeof(signature), &signature_length);
+
+ CHECK_EQUAL(PSA_SUCCESS, status);
+ CHECK(signature_length > 0);
+
+ /* Verify the signature */
+ status = m_crypto_client->verify_message(key_id,
+ PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), message, sizeof(message),
+ signature, signature_length);
+ CHECK_EQUAL(PSA_SUCCESS, status);
+
+ /* Change the message and expect verify to fail */
+ message[0] = 0x72;
+ status = m_crypto_client->verify_message(key_id,
+ PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), message, sizeof(message),
+ signature, signature_length);
+ CHECK_EQUAL(PSA_ERROR_INVALID_SIGNATURE, status);
+
+ /* Remove the key */
+ status = m_crypto_client->destroy_key(key_id);
+ CHECK_EQUAL(PSA_SUCCESS, status);
+}
+
void crypto_service_scenarios::signAndVerifyEat()
{
/* Sign and verify a hash using EAT key type and algorithm */
@@ -348,11 +398,11 @@ void crypto_service_scenarios::asymEncryptDecrypt()
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id;
- psa_set_key_id(&attributes, 14);
+ psa_set_key_id(&attributes, 15);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
- psa_set_key_bits(&attributes, 256);
+ psa_set_key_bits(&attributes, 1024);
/* Generate a key */
status = m_crypto_client->generate_key(&attributes, &key_id);
@@ -394,7 +444,7 @@ void crypto_service_scenarios::asymEncryptDecryptWithSalt()
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id;
- psa_set_key_id(&attributes, 15);
+ psa_set_key_id(&attributes, 16);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256));
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
@@ -501,3 +551,227 @@ void crypto_service_scenarios::generateRandomNumbers()
CHECK(memcmp(num9_64bit, num10_64bit, sizeof(num9_64bit)) != 0);
CHECK(memcmp(num11_128bit, num12_128bit, sizeof(num11_128bit)) != 0);
}
+
+void crypto_service_scenarios::verifypkcs7signature(void)
+{
+ psa_status_t status;
+
+ unsigned char hash[] = { 0x56, 0xcf, 0x42, 0x1c, 0x35, 0x78, 0x2f, 0x6f, 0x77, 0xdd, 0x2b,
+ 0x44, 0x0b, 0xb4, 0xdf, 0x34, 0x56, 0x6b, 0x69, 0xc4, 0x51, 0x9b,
+ 0x47, 0x7b, 0x64, 0xfd, 0x56, 0x56, 0x25, 0xd6, 0x47, 0x27 };
+
+ unsigned char public_key[] = {
+ 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+ 0x14, 0x5a, 0x8e, 0x8a, 0x75, 0x09, 0xe8, 0x96, 0xed, 0x26, 0x29, 0xca, 0xd6, 0x01,
+ 0xfc, 0xce, 0xb4, 0x70, 0x70, 0x68, 0x55, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x38, 0x32, 0x32, 0x30, 0x38, 0x31,
+ 0x30, 0x33, 0x37, 0x5a, 0x17, 0x0d, 0x33, 0x33, 0x30, 0x38, 0x31, 0x39, 0x30, 0x38,
+ 0x31, 0x30, 0x33, 0x37, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x82,
+ 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+ 0x01, 0x01, 0x00, 0xd5, 0x55, 0x6e, 0x9f, 0xa8, 0x92, 0x68, 0x2b, 0x3c, 0xbd, 0xbc,
+ 0x37, 0xd5, 0x2f, 0x5e, 0xf1, 0x70, 0x76, 0x7b, 0x5e, 0x54, 0xd5, 0x89, 0x90, 0x5a,
+ 0xeb, 0x01, 0x63, 0x6c, 0x34, 0xe9, 0x54, 0xa0, 0x06, 0x31, 0xf0, 0xff, 0x9b, 0xd8,
+ 0x80, 0x2a, 0x3d, 0x42, 0x37, 0xab, 0x37, 0xd9, 0x22, 0xff, 0x66, 0xd1, 0x02, 0xb9,
+ 0xbc, 0xe2, 0x8a, 0x45, 0xc8, 0xfe, 0x6f, 0x6c, 0xfc, 0xca, 0x5e, 0x90, 0x5c, 0xb1,
+ 0xc6, 0xd8, 0x2f, 0x59, 0xac, 0x46, 0x36, 0x0c, 0x7d, 0x39, 0xc4, 0x5f, 0xd4, 0xae,
+ 0x1f, 0x81, 0x6e, 0x79, 0xdf, 0xe5, 0xfd, 0x8f, 0xbb, 0x28, 0xc8, 0x7d, 0x0e, 0x46,
+ 0x66, 0xb9, 0x4b, 0x30, 0xf6, 0x9b, 0xc2, 0xff, 0x0d, 0xc7, 0x93, 0x5d, 0xd8, 0xbb,
+ 0x00, 0x7b, 0x35, 0x6a, 0x79, 0xa8, 0x47, 0xd6, 0xf5, 0x54, 0xc6, 0x28, 0x88, 0x58,
+ 0x7d, 0x34, 0xdc, 0x41, 0x29, 0x9c, 0xef, 0x54, 0x00, 0x2c, 0xce, 0xcd, 0xad, 0x07,
+ 0x38, 0x98, 0x07, 0x05, 0xf9, 0x4a, 0x67, 0x1e, 0xeb, 0x14, 0x33, 0x73, 0x6e, 0x3b,
+ 0xa4, 0x4d, 0xc5, 0x0b, 0x6a, 0xfb, 0x76, 0xa5, 0xef, 0x4f, 0xb4, 0x59, 0xf0, 0x2a,
+ 0xce, 0x8c, 0xdc, 0xdf, 0xd1, 0x3d, 0x52, 0x36, 0xb9, 0x05, 0xc4, 0x11, 0x7f, 0xe8,
+ 0x5a, 0x7f, 0xfc, 0xfc, 0xdc, 0x53, 0x62, 0x34, 0x69, 0xa7, 0x67, 0x49, 0x74, 0xb9,
+ 0xd1, 0x40, 0x72, 0x7a, 0x06, 0x8b, 0xb6, 0xc5, 0x0e, 0x4c, 0x99, 0xf8, 0xcb, 0x3a,
+ 0x96, 0xe9, 0x8e, 0x49, 0x87, 0xe8, 0xa6, 0x80, 0x43, 0x0e, 0x66, 0x87, 0x9a, 0xca,
+ 0xd6, 0x58, 0x97, 0x5d, 0xd4, 0x9f, 0x2f, 0x00, 0x9b, 0xed, 0x94, 0x8f, 0x13, 0xc2,
+ 0xd8, 0xd1, 0x35, 0x24, 0x96, 0x61, 0x66, 0xed, 0xa7, 0xd1, 0x36, 0xb4, 0xe9, 0x28,
+ 0x9c, 0x36, 0xf9, 0x2d, 0x38, 0x03, 0xaf, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53,
+ 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc1,
+ 0xb8, 0xa7, 0xa0, 0xb9, 0x1c, 0x8c, 0x02, 0x5a, 0x17, 0x3e, 0x68, 0x94, 0xc0, 0x88,
+ 0xcb, 0x4e, 0x63, 0x7f, 0x2d, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+ 0x30, 0x16, 0x80, 0x14, 0xc1, 0xb8, 0xa7, 0xa0, 0xb9, 0x1c, 0x8c, 0x02, 0x5a, 0x17,
+ 0x3e, 0x68, 0x94, 0xc0, 0x88, 0xcb, 0x4e, 0x63, 0x7f, 0x2d, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+ 0x03, 0x82, 0x01, 0x01, 0x00, 0x49, 0x3a, 0x18, 0xc9, 0x09, 0x77, 0xfa, 0xde, 0xbe,
+ 0xd4, 0x1c, 0xdb, 0xbd, 0x42, 0x53, 0x25, 0x21, 0x45, 0xe3, 0xcc, 0xe8, 0xa4, 0xe5,
+ 0x68, 0xf6, 0xba, 0x09, 0x01, 0xad, 0x9e, 0x75, 0x9f, 0x1e, 0x5c, 0x07, 0xef, 0xcd,
+ 0x0b, 0x4a, 0x26, 0x5b, 0x03, 0x52, 0x04, 0xb5, 0x27, 0x5c, 0x18, 0x1e, 0x58, 0x54,
+ 0xa3, 0xc8, 0xbd, 0x87, 0xc3, 0xa1, 0x7d, 0x8a, 0x9b, 0x3e, 0xa8, 0xbf, 0x76, 0xa8,
+ 0x3c, 0xaa, 0x54, 0xfa, 0x78, 0x30, 0xfc, 0xa8, 0x52, 0xca, 0x20, 0x8d, 0x72, 0x29,
+ 0x61, 0x38, 0x10, 0xcb, 0x36, 0x50, 0x3f, 0xf3, 0x8c, 0xc6, 0xb5, 0xd6, 0xa3, 0xf0,
+ 0x6f, 0x76, 0x30, 0xb7, 0xbd, 0x2b, 0x5d, 0x2d, 0x10, 0x63, 0x17, 0xbd, 0x0f, 0x54,
+ 0x88, 0xb6, 0x78, 0x6e, 0x06, 0x8d, 0x65, 0x0e, 0x26, 0xea, 0x4e, 0x3c, 0xb4, 0xf0,
+ 0x74, 0x0b, 0xd6, 0xef, 0x5a, 0x04, 0x77, 0x66, 0xc8, 0x74, 0x5e, 0xe1, 0xd7, 0x37,
+ 0xcc, 0x74, 0x5f, 0x32, 0xb1, 0x42, 0x70, 0x5f, 0x05, 0xfa, 0x9f, 0x0d, 0xb6, 0xf7,
+ 0xd9, 0xf7, 0x42, 0xbe, 0x2b, 0xf4, 0x5f, 0xf1, 0x65, 0x2c, 0xaf, 0xde, 0xfb, 0xf4,
+ 0x69, 0xa4, 0x45, 0x1f, 0xa0, 0x39, 0x37, 0xda, 0x81, 0x07, 0xd2, 0x3e, 0xd9, 0x5b,
+ 0xc4, 0xb2, 0x7c, 0xea, 0x17, 0xaf, 0x05, 0x68, 0x70, 0xfd, 0x85, 0x81, 0x15, 0x16,
+ 0xa8, 0xc3, 0xbf, 0xbf, 0x00, 0xbf, 0x17, 0xef, 0x78, 0xc9, 0x40, 0xd1, 0x2a, 0x11,
+ 0x00, 0xcc, 0x39, 0x40, 0xae, 0x79, 0x30, 0xa8, 0x27, 0xb6, 0x6c, 0x64, 0x26, 0xcb,
+ 0x20, 0xdb, 0xad, 0x75, 0x75, 0xe8, 0xa0, 0x50, 0x84, 0x2b, 0x00, 0x93, 0xdf, 0xf8,
+ 0x79, 0x69, 0xef, 0x6d, 0x1c, 0xdf, 0xc6, 0x40, 0x39, 0xc9, 0x8e, 0xda, 0x70, 0xcf,
+ 0x1c, 0x4d, 0x78, 0xc6, 0x9c, 0xa7, 0xe0, 0x8e, 0x25
+ };
+
+ unsigned char signature[] = {
+ 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
+ 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30, 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f,
+ 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x14, 0x5a, 0x8e, 0x8a, 0x75, 0x09, 0xe8, 0x96, 0xed, 0x26,
+ 0x29, 0xca, 0xd6, 0x01, 0xfc, 0xce, 0xb4, 0x70, 0x70, 0x68, 0x55, 0x30, 0x0d, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13,
+ 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73,
+ 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x38, 0x32,
+ 0x32, 0x30, 0x38, 0x31, 0x30, 0x33, 0x37, 0x5a, 0x17, 0x0d, 0x33, 0x33, 0x30, 0x38,
+ 0x31, 0x39, 0x30, 0x38, 0x31, 0x30, 0x33, 0x37, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30,
+ 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50,
+ 0x4b, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
+ 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd5, 0x55, 0x6e, 0x9f, 0xa8, 0x92, 0x68,
+ 0x2b, 0x3c, 0xbd, 0xbc, 0x37, 0xd5, 0x2f, 0x5e, 0xf1, 0x70, 0x76, 0x7b, 0x5e, 0x54,
+ 0xd5, 0x89, 0x90, 0x5a, 0xeb, 0x01, 0x63, 0x6c, 0x34, 0xe9, 0x54, 0xa0, 0x06, 0x31,
+ 0xf0, 0xff, 0x9b, 0xd8, 0x80, 0x2a, 0x3d, 0x42, 0x37, 0xab, 0x37, 0xd9, 0x22, 0xff,
+ 0x66, 0xd1, 0x02, 0xb9, 0xbc, 0xe2, 0x8a, 0x45, 0xc8, 0xfe, 0x6f, 0x6c, 0xfc, 0xca,
+ 0x5e, 0x90, 0x5c, 0xb1, 0xc6, 0xd8, 0x2f, 0x59, 0xac, 0x46, 0x36, 0x0c, 0x7d, 0x39,
+ 0xc4, 0x5f, 0xd4, 0xae, 0x1f, 0x81, 0x6e, 0x79, 0xdf, 0xe5, 0xfd, 0x8f, 0xbb, 0x28,
+ 0xc8, 0x7d, 0x0e, 0x46, 0x66, 0xb9, 0x4b, 0x30, 0xf6, 0x9b, 0xc2, 0xff, 0x0d, 0xc7,
+ 0x93, 0x5d, 0xd8, 0xbb, 0x00, 0x7b, 0x35, 0x6a, 0x79, 0xa8, 0x47, 0xd6, 0xf5, 0x54,
+ 0xc6, 0x28, 0x88, 0x58, 0x7d, 0x34, 0xdc, 0x41, 0x29, 0x9c, 0xef, 0x54, 0x00, 0x2c,
+ 0xce, 0xcd, 0xad, 0x07, 0x38, 0x98, 0x07, 0x05, 0xf9, 0x4a, 0x67, 0x1e, 0xeb, 0x14,
+ 0x33, 0x73, 0x6e, 0x3b, 0xa4, 0x4d, 0xc5, 0x0b, 0x6a, 0xfb, 0x76, 0xa5, 0xef, 0x4f,
+ 0xb4, 0x59, 0xf0, 0x2a, 0xce, 0x8c, 0xdc, 0xdf, 0xd1, 0x3d, 0x52, 0x36, 0xb9, 0x05,
+ 0xc4, 0x11, 0x7f, 0xe8, 0x5a, 0x7f, 0xfc, 0xfc, 0xdc, 0x53, 0x62, 0x34, 0x69, 0xa7,
+ 0x67, 0x49, 0x74, 0xb9, 0xd1, 0x40, 0x72, 0x7a, 0x06, 0x8b, 0xb6, 0xc5, 0x0e, 0x4c,
+ 0x99, 0xf8, 0xcb, 0x3a, 0x96, 0xe9, 0x8e, 0x49, 0x87, 0xe8, 0xa6, 0x80, 0x43, 0x0e,
+ 0x66, 0x87, 0x9a, 0xca, 0xd6, 0x58, 0x97, 0x5d, 0xd4, 0x9f, 0x2f, 0x00, 0x9b, 0xed,
+ 0x94, 0x8f, 0x13, 0xc2, 0xd8, 0xd1, 0x35, 0x24, 0x96, 0x61, 0x66, 0xed, 0xa7, 0xd1,
+ 0x36, 0xb4, 0xe9, 0x28, 0x9c, 0x36, 0xf9, 0x2d, 0x38, 0x03, 0xaf, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+ 0x16, 0x04, 0x14, 0xc1, 0xb8, 0xa7, 0xa0, 0xb9, 0x1c, 0x8c, 0x02, 0x5a, 0x17, 0x3e,
+ 0x68, 0x94, 0xc0, 0x88, 0xcb, 0x4e, 0x63, 0x7f, 0x2d, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc1, 0xb8, 0xa7, 0xa0, 0xb9, 0x1c,
+ 0x8c, 0x02, 0x5a, 0x17, 0x3e, 0x68, 0x94, 0xc0, 0x88, 0xcb, 0x4e, 0x63, 0x7f, 0x2d,
+ 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x49, 0x3a, 0x18, 0xc9, 0x09,
+ 0x77, 0xfa, 0xde, 0xbe, 0xd4, 0x1c, 0xdb, 0xbd, 0x42, 0x53, 0x25, 0x21, 0x45, 0xe3,
+ 0xcc, 0xe8, 0xa4, 0xe5, 0x68, 0xf6, 0xba, 0x09, 0x01, 0xad, 0x9e, 0x75, 0x9f, 0x1e,
+ 0x5c, 0x07, 0xef, 0xcd, 0x0b, 0x4a, 0x26, 0x5b, 0x03, 0x52, 0x04, 0xb5, 0x27, 0x5c,
+ 0x18, 0x1e, 0x58, 0x54, 0xa3, 0xc8, 0xbd, 0x87, 0xc3, 0xa1, 0x7d, 0x8a, 0x9b, 0x3e,
+ 0xa8, 0xbf, 0x76, 0xa8, 0x3c, 0xaa, 0x54, 0xfa, 0x78, 0x30, 0xfc, 0xa8, 0x52, 0xca,
+ 0x20, 0x8d, 0x72, 0x29, 0x61, 0x38, 0x10, 0xcb, 0x36, 0x50, 0x3f, 0xf3, 0x8c, 0xc6,
+ 0xb5, 0xd6, 0xa3, 0xf0, 0x6f, 0x76, 0x30, 0xb7, 0xbd, 0x2b, 0x5d, 0x2d, 0x10, 0x63,
+ 0x17, 0xbd, 0x0f, 0x54, 0x88, 0xb6, 0x78, 0x6e, 0x06, 0x8d, 0x65, 0x0e, 0x26, 0xea,
+ 0x4e, 0x3c, 0xb4, 0xf0, 0x74, 0x0b, 0xd6, 0xef, 0x5a, 0x04, 0x77, 0x66, 0xc8, 0x74,
+ 0x5e, 0xe1, 0xd7, 0x37, 0xcc, 0x74, 0x5f, 0x32, 0xb1, 0x42, 0x70, 0x5f, 0x05, 0xfa,
+ 0x9f, 0x0d, 0xb6, 0xf7, 0xd9, 0xf7, 0x42, 0xbe, 0x2b, 0xf4, 0x5f, 0xf1, 0x65, 0x2c,
+ 0xaf, 0xde, 0xfb, 0xf4, 0x69, 0xa4, 0x45, 0x1f, 0xa0, 0x39, 0x37, 0xda, 0x81, 0x07,
+ 0xd2, 0x3e, 0xd9, 0x5b, 0xc4, 0xb2, 0x7c, 0xea, 0x17, 0xaf, 0x05, 0x68, 0x70, 0xfd,
+ 0x85, 0x81, 0x15, 0x16, 0xa8, 0xc3, 0xbf, 0xbf, 0x00, 0xbf, 0x17, 0xef, 0x78, 0xc9,
+ 0x40, 0xd1, 0x2a, 0x11, 0x00, 0xcc, 0x39, 0x40, 0xae, 0x79, 0x30, 0xa8, 0x27, 0xb6,
+ 0x6c, 0x64, 0x26, 0xcb, 0x20, 0xdb, 0xad, 0x75, 0x75, 0xe8, 0xa0, 0x50, 0x84, 0x2b,
+ 0x00, 0x93, 0xdf, 0xf8, 0x79, 0x69, 0xef, 0x6d, 0x1c, 0xdf, 0xc6, 0x40, 0x39, 0xc9,
+ 0x8e, 0xda, 0x70, 0xcf, 0x1c, 0x4d, 0x78, 0xc6, 0x9c, 0xa7, 0xe0, 0x8e, 0x25, 0x31,
+ 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02, 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13,
+ 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73,
+ 0x74, 0x20, 0x50, 0x4b, 0x31, 0x02, 0x14, 0x5a, 0x8e, 0x8a, 0x75, 0x09, 0xe8, 0x96,
+ 0xed, 0x26, 0x29, 0xca, 0xd6, 0x01, 0xfc, 0xce, 0xb4, 0x70, 0x70, 0x68, 0x55, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+ 0x00, 0x04, 0x82, 0x01, 0x00, 0x33, 0x93, 0x6d, 0x8d, 0xf6, 0xf9, 0x3f, 0xbe, 0x37,
+ 0xed, 0xc7, 0xb3, 0xf6, 0xd3, 0xd3, 0x55, 0x2e, 0x30, 0x98, 0xd9, 0x50, 0x7f, 0xc5,
+ 0x3c, 0x12, 0x9c, 0xcf, 0x53, 0x1e, 0x0d, 0xd7, 0x5c, 0x94, 0x67, 0x15, 0x07, 0x17,
+ 0x6d, 0x41, 0x93, 0x9d, 0x1a, 0x36, 0x92, 0x8c, 0x46, 0xb9, 0x3a, 0x4d, 0xed, 0xd6,
+ 0xe0, 0x23, 0x50, 0x7e, 0xfd, 0x4d, 0xd9, 0x59, 0xbc, 0xaf, 0x7b, 0x4f, 0x83, 0x99,
+ 0xd4, 0x11, 0xf5, 0xb4, 0x24, 0xba, 0x35, 0x87, 0x22, 0xbf, 0xa6, 0x3d, 0xe0, 0xcb,
+ 0x52, 0xbd, 0xcb, 0xb0, 0xae, 0x86, 0xb8, 0x97, 0x8e, 0xc7, 0xc5, 0x9a, 0x14, 0x15,
+ 0xc8, 0x71, 0x57, 0x40, 0x1c, 0x47, 0x11, 0x68, 0xfd, 0x27, 0xe4, 0xde, 0x2d, 0xbb,
+ 0x27, 0xea, 0xa3, 0xe9, 0x75, 0xe3, 0x74, 0x33, 0x87, 0x04, 0xe1, 0x72, 0x1a, 0x24,
+ 0x75, 0x94, 0xfd, 0x6a, 0x9c, 0xef, 0xc5, 0x4b, 0xee, 0x86, 0x51, 0x11, 0xb2, 0x59,
+ 0x07, 0x33, 0x5c, 0xa1, 0x11, 0xd0, 0x83, 0xd2, 0x99, 0x40, 0x92, 0xe8, 0xc8, 0xe5,
+ 0x20, 0xd9, 0x0e, 0x25, 0x2b, 0x27, 0x92, 0xc7, 0xbc, 0xe0, 0xb7, 0xd8, 0x16, 0x15,
+ 0x38, 0x25, 0xfc, 0x85, 0x75, 0xaf, 0x9c, 0x12, 0x87, 0x88, 0x2f, 0x6d, 0xd6, 0x24,
+ 0x89, 0xe5, 0x5e, 0x0c, 0x0d, 0x03, 0xf6, 0x5e, 0x03, 0xf9, 0xf7, 0x6b, 0x92, 0xeb,
+ 0xe4, 0x4b, 0xab, 0x58, 0x81, 0xe8, 0x73, 0x90, 0x0e, 0x84, 0x9e, 0x9d, 0x24, 0x25,
+ 0x91, 0x75, 0x8a, 0xdc, 0x92, 0xe6, 0x42, 0x52, 0x38, 0xcf, 0x63, 0xd9, 0xb7, 0xe6,
+ 0xcd, 0x80, 0x35, 0x8a, 0xe4, 0x1d, 0xb9, 0xe2, 0x86, 0xc2, 0xbf, 0x44, 0x83, 0x20,
+ 0x3a, 0x59, 0x9b, 0xbf, 0x64, 0xc0, 0xae, 0x2a, 0x6b, 0xe5, 0x06, 0x4a, 0x86, 0x26,
+ 0xb3, 0x48, 0xdb, 0xad, 0x31, 0x2f, 0x71, 0xef, 0x33,
+ };
+
+ /* Inject error into hash value and expect failure */
+ hash[0] = ~hash[0];
+ status = m_crypto_client->verify_pkcs7_signature((const uint8_t *)signature,
+ sizeof(signature), (const uint8_t *)hash,
+ sizeof(hash), (const uint8_t *)public_key,
+ sizeof(public_key));
+ hash[0] = ~hash[0];
+
+ /*
+ * If the functionality to be tested here is missing from mbedtls let's return.
+ * Expected: MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED
+ */
+ if(status == (-0x0072))
+ return;
+
+ CHECK(status != 0);
+
+ /* Inject error into the public key format and expect failure */
+ public_key[0] = ~public_key[0];
+ status = m_crypto_client->verify_pkcs7_signature((const uint8_t *)signature,
+ sizeof(signature), (const uint8_t *)hash,
+ sizeof(hash), (const uint8_t *)public_key,
+ sizeof(public_key));
+ public_key[0] = ~public_key[0];
+
+ CHECK(status != 0);
+
+ /* Inject error into the public key value and expect failure
+ * The beginning of the key is found by using parser.
+ */
+ int first_byte_of_public_key = 152;
+ public_key[first_byte_of_public_key] = ~public_key[first_byte_of_public_key];
+ status = m_crypto_client->verify_pkcs7_signature((const uint8_t *)signature,
+ sizeof(signature), (const uint8_t *)hash,
+ sizeof(hash), (const uint8_t *)public_key,
+ sizeof(public_key));
+ public_key[first_byte_of_public_key] = ~public_key[first_byte_of_public_key];
+
+ CHECK(status != 0);
+
+ /* Inject error into the signature format and expect failure */
+ signature[0] = ~signature[0];
+ status = m_crypto_client->verify_pkcs7_signature((const uint8_t *)signature,
+ sizeof(signature), (const uint8_t *)hash,
+ sizeof(hash), (const uint8_t *)public_key,
+ sizeof(public_key));
+ signature[0] = ~signature[0];
+
+ CHECK(status != 0);
+
+ /* Inject error into the signature value what is at the end of the vector */
+ signature[sizeof(signature) - 1] = ~signature[sizeof(signature) - 1];
+ status = m_crypto_client->verify_pkcs7_signature((const uint8_t *)signature,
+ sizeof(signature), (const uint8_t *)hash,
+ sizeof(hash), (const uint8_t *)public_key,
+ sizeof(public_key));
+ signature[sizeof(signature) - 1] = ~signature[sizeof(signature) - 1];
+
+ CHECK(status != 0);
+
+ /* Verify correct signature */
+ status = m_crypto_client->verify_pkcs7_signature((const uint8_t *)signature,
+ sizeof(signature), (const uint8_t *)hash,
+ sizeof(hash), (const uint8_t *)public_key,
+ sizeof(public_key));
+
+ CHECK(status == 0);
+} \ No newline at end of file
diff --git a/components/service/crypto/test/service/crypto_service_scenarios.h b/components/service/crypto/test/service/crypto_service_scenarios.h
index c65eba262..808187713 100644
--- a/components/service/crypto/test/service/crypto_service_scenarios.h
+++ b/components/service/crypto/test/service/crypto_service_scenarios.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -24,6 +24,7 @@ public:
void asymEncryptDecrypt();
void asymEncryptDecryptWithSalt();
void signAndVerifyHash();
+ void signAndVerifyMessage();
void signAndVerifyEat();
void exportAndImportKeyPair();
void exportPublicKey();
@@ -31,6 +32,7 @@ public:
void generateVolatileKeys();
void copyKey();
void purgeKey();
+ void verifypkcs7signature(void);
private:
crypto_client *m_crypto_client;
diff --git a/components/service/crypto/test/service/extension/cipher/packed-c/cipher_service_packedc_tests.cpp b/components/service/crypto/test/service/extension/cipher/packed-c/cipher_service_packedc_tests.cpp
index d0e7f3868..4cac762da 100644
--- a/components/service/crypto/test/service/extension/cipher/packed-c/cipher_service_packedc_tests.cpp
+++ b/components/service/crypto/test/service/extension/cipher/packed-c/cipher_service_packedc_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,22 +17,19 @@ TEST_GROUP(CryptoCipherServicePackedcTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_crypto_service_context = NULL;
m_scenarios = NULL;
service_locator_init();
- m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0");
CHECK_TRUE(m_crypto_service_context);
- m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_crypto_service_context);
+ CHECK_TRUE(m_rpc_session);
- m_scenarios = new cipher_service_scenarios(new packedc_crypto_client(caller));
+ m_scenarios = new cipher_service_scenarios(new packedc_crypto_client(m_rpc_session));
}
void teardown()
@@ -40,14 +37,18 @@ TEST_GROUP(CryptoCipherServicePackedcTests)
delete m_scenarios;
m_scenarios = NULL;
- service_context_close(m_crypto_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_crypto_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_crypto_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_crypto_service_context);
- m_crypto_service_context = NULL;
+ service_context_relinquish(m_crypto_service_context);
+ m_crypto_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_crypto_service_context;
cipher_service_scenarios *m_scenarios;
};
@@ -60,4 +61,4 @@ TEST(CryptoCipherServicePackedcTests, encryptDecryptRoundtrip)
TEST(CryptoCipherServicePackedcTests, cipherAbort)
{
m_scenarios->cipherAbort();
-}
+} \ No newline at end of file
diff --git a/components/service/crypto/test/service/extension/hash/hash_service_scenarios.cpp b/components/service/crypto/test/service/extension/hash/hash_service_scenarios.cpp
index b02cfd184..95f8955c5 100644
--- a/components/service/crypto/test/service/extension/hash/hash_service_scenarios.cpp
+++ b/components/service/crypto/test/service/extension/hash/hash_service_scenarios.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -112,9 +112,6 @@ void hash_service_scenarios::hashAbort()
create_ref_input(input_size);
- uint8_t hash[PSA_HASH_MAX_SIZE];
- size_t hash_len;
-
uint32_t op_handle = 0;
psa_status_t status;
diff --git a/components/service/crypto/test/service/extension/hash/packed-c/hash_service_packedc_tests.cpp b/components/service/crypto/test/service/extension/hash/packed-c/hash_service_packedc_tests.cpp
index 6bc55cf5a..530c17501 100644
--- a/components/service/crypto/test/service/extension/hash/packed-c/hash_service_packedc_tests.cpp
+++ b/components/service/crypto/test/service/extension/hash/packed-c/hash_service_packedc_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,22 +17,19 @@ TEST_GROUP(CryptoHashServicePackedcTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_crypto_service_context = NULL;
m_scenarios = NULL;
service_locator_init();
- m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0");
CHECK_TRUE(m_crypto_service_context);
- m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_crypto_service_context);
+ CHECK_TRUE(m_rpc_session);
- m_scenarios = new hash_service_scenarios(new packedc_crypto_client(caller));
+ m_scenarios = new hash_service_scenarios(new packedc_crypto_client(m_rpc_session));
}
void teardown()
@@ -40,14 +37,18 @@ TEST_GROUP(CryptoHashServicePackedcTests)
delete m_scenarios;
m_scenarios = NULL;
- service_context_close(m_crypto_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_crypto_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_crypto_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_crypto_service_context);
- m_crypto_service_context = NULL;
+ service_context_relinquish(m_crypto_service_context);
+ m_crypto_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_crypto_service_context;
hash_service_scenarios *m_scenarios;
};
@@ -65,4 +66,4 @@ TEST(CryptoHashServicePackedcTests, hashAndVerify)
TEST(CryptoHashServicePackedcTests, hashAbort)
{
m_scenarios->hashAbort();
-}
+} \ No newline at end of file
diff --git a/components/service/crypto/test/service/extension/key_derivation/packed-c/key_derivation_service_packedc_tests.cpp b/components/service/crypto/test/service/extension/key_derivation/packed-c/key_derivation_service_packedc_tests.cpp
index 261bf988d..8212bc246 100644
--- a/components/service/crypto/test/service/extension/key_derivation/packed-c/key_derivation_service_packedc_tests.cpp
+++ b/components/service/crypto/test/service/extension/key_derivation/packed-c/key_derivation_service_packedc_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,22 +17,19 @@ TEST_GROUP(CryptoKeyDerivationServicePackedcTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_crypto_service_context = NULL;
m_scenarios = NULL;
service_locator_init();
- m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0");
CHECK_TRUE(m_crypto_service_context);
- m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_crypto_service_context);
+ CHECK_TRUE(m_rpc_session);
- m_scenarios = new key_derivation_service_scenarios(new packedc_crypto_client(caller));
+ m_scenarios = new key_derivation_service_scenarios(new packedc_crypto_client(m_rpc_session));
}
void teardown()
@@ -40,14 +37,18 @@ TEST_GROUP(CryptoKeyDerivationServicePackedcTests)
delete m_scenarios;
m_scenarios = NULL;
- service_context_close(m_crypto_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_crypto_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_crypto_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_crypto_service_context);
- m_crypto_service_context = NULL;
+ service_context_relinquish(m_crypto_service_context);
+ m_crypto_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_crypto_service_context;
key_derivation_service_scenarios *m_scenarios;
};
@@ -65,4 +66,4 @@ TEST(CryptoKeyDerivationServicePackedcTests, hkdfDeriveBytes)
TEST(CryptoKeyDerivationServicePackedcTests, deriveAbort)
{
m_scenarios->deriveAbort();
-}
+} \ No newline at end of file
diff --git a/components/service/crypto/test/service/extension/mac/packed-c/mac_service_packedc_tests.cpp b/components/service/crypto/test/service/extension/mac/packed-c/mac_service_packedc_tests.cpp
index 6ead05429..b8f4d97d1 100644
--- a/components/service/crypto/test/service/extension/mac/packed-c/mac_service_packedc_tests.cpp
+++ b/components/service/crypto/test/service/extension/mac/packed-c/mac_service_packedc_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,22 +17,19 @@ TEST_GROUP(CryptoMacServicePackedcTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_crypto_service_context = NULL;
m_scenarios = NULL;
service_locator_init();
- m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0");
CHECK_TRUE(m_crypto_service_context);
- m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_crypto_service_context);
+ CHECK_TRUE(m_rpc_session);
- m_scenarios = new mac_service_scenarios(new packedc_crypto_client(caller));
+ m_scenarios = new mac_service_scenarios(new packedc_crypto_client(m_rpc_session));
}
void teardown()
@@ -40,14 +37,18 @@ TEST_GROUP(CryptoMacServicePackedcTests)
delete m_scenarios;
m_scenarios = NULL;
- service_context_close(m_crypto_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_crypto_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_crypto_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_crypto_service_context);
- m_crypto_service_context = NULL;
+ service_context_relinquish(m_crypto_service_context);
+ m_crypto_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_crypto_service_context;
mac_service_scenarios *m_scenarios;
};
@@ -60,4 +61,4 @@ TEST(CryptoMacServicePackedcTests, signAndVerify)
TEST(CryptoMacServicePackedcTests, macAbort)
{
m_scenarios->macAbort();
-}
+} \ No newline at end of file
diff --git a/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp b/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp
index 79eddfbb8..bc0f90834 100644
--- a/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp
+++ b/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,22 +17,19 @@ TEST_GROUP(CryptoServicePackedcTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_crypto_service_context = NULL;
m_scenarios = NULL;
service_locator_init();
- m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0");
CHECK_TRUE(m_crypto_service_context);
- m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_crypto_service_context);
+ CHECK_TRUE(m_rpc_session);
- m_scenarios = new crypto_service_scenarios(new packedc_crypto_client(caller));
+ m_scenarios = new crypto_service_scenarios(new packedc_crypto_client(m_rpc_session));
}
void teardown()
@@ -40,14 +37,18 @@ TEST_GROUP(CryptoServicePackedcTests)
delete m_scenarios;
m_scenarios = NULL;
- service_context_close(m_crypto_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_crypto_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_crypto_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_crypto_service_context);
- m_crypto_service_context = NULL;
+ service_context_relinquish(m_crypto_service_context);
+ m_crypto_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_crypto_service_context;
crypto_service_scenarios *m_scenarios;
};
@@ -87,6 +88,11 @@ TEST(CryptoServicePackedcTests, signAndVerifyHash)
m_scenarios->signAndVerifyHash();
}
+TEST(CryptoServicePackedcTests, signAndVerifyMessage)
+{
+ m_scenarios->signAndVerifyMessage();
+}
+
TEST(CryptoServicePackedcTests, signAndVerifyEat)
{
m_scenarios->signAndVerifyEat();
@@ -106,3 +112,8 @@ TEST(CryptoServicePackedcTests, generateRandomNumbers)
{
m_scenarios->generateRandomNumbers();
}
+
+TEST(CryptoServicePackedcTests, verifyPkcs7Signature)
+{
+ m_scenarios->verifypkcs7signature();
+}
diff --git a/components/service/crypto/test/service/protobuf/crypto_service_protobuf_tests.cpp b/components/service/crypto/test/service/protobuf/crypto_service_protobuf_tests.cpp
index 1230752c0..56030eefc 100644
--- a/components/service/crypto/test/service/protobuf/crypto_service_protobuf_tests.cpp
+++ b/components/service/crypto/test/service/protobuf/crypto_service_protobuf_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,22 +17,19 @@ TEST_GROUP(CryptoServiceProtobufTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_crypto_service_context = NULL;
m_scenarios = NULL;
service_locator_init();
- m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto-protobuf:0");
CHECK_TRUE(m_crypto_service_context);
- m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PROTOBUF, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_crypto_service_context);
+ CHECK_TRUE(m_rpc_session);
- m_scenarios = new crypto_service_scenarios(new protobuf_crypto_client(caller));
+ m_scenarios = new crypto_service_scenarios(new protobuf_crypto_client(m_rpc_session));
}
void teardown()
@@ -40,14 +37,18 @@ TEST_GROUP(CryptoServiceProtobufTests)
delete m_scenarios;
m_scenarios = NULL;
- service_context_close(m_crypto_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_crypto_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_crypto_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_crypto_service_context);
- m_crypto_service_context = NULL;
+ service_context_relinquish(m_crypto_service_context);
+ m_crypto_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_crypto_service_context;
crypto_service_scenarios *m_scenarios;
};
@@ -77,6 +78,11 @@ TEST(CryptoServiceProtobufTests, signAndVerifyHash)
m_scenarios->signAndVerifyHash();
}
+TEST(CryptoServiceProtobufTests, signAndVerifyMessage)
+{
+ m_scenarios->signAndVerifyMessage();
+}
+
TEST(CryptoServiceProtobufTests, asymEncryptDecrypt)
{
m_scenarios->asymEncryptDecrypt();
diff --git a/components/service/discovery/client/discovery_client.c b/components/service/discovery/client/discovery_client.c
deleted file mode 100644
index 5fc2ff32d..000000000
--- a/components/service/discovery/client/discovery_client.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <string.h>
-#include <common/tlv/tlv.h>
-#include <protocols/service/discovery/packed-c/get_service_info.h>
-#include <protocols/service/discovery/packed-c/opcodes.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include "discovery_client.h"
-
-psa_status_t discovery_client_get_service_info(
- struct service_client *service_client)
-{
- psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
- rpc_call_handle call_handle;
- uint8_t *req_buf;
-
- call_handle = rpc_caller_begin(service_client->caller, &req_buf, 0);
-
- if (call_handle) {
-
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
-
- service_client->rpc_status = rpc_caller_invoke(service_client->caller, call_handle,
- TS_DISCOVERY_OPCODE_GET_SERVICE_INFO, &opstatus, &resp_buf, &resp_len);
-
- if (service_client->rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- psa_status = opstatus;
-
- if (psa_status == PSA_SUCCESS) {
-
- if (resp_len >= sizeof(struct ts_discovery_get_service_info_out)) {
-
- struct ts_discovery_get_service_info_out resp_msg;
- memcpy(&resp_msg, resp_buf, sizeof(struct ts_discovery_get_service_info_out));
-
- service_client->service_info.supported_encodings =
- resp_msg.supported_encodings;
-
- service_client->service_info.max_payload =
- resp_msg.max_payload;
- }
- else {
- /* Failed to decode response message */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
- }
- }
-
- rpc_caller_end(service_client->caller, call_handle);
- }
-
- return psa_status;
-}
diff --git a/components/service/discovery/client/discovery_client.h b/components/service/discovery/client/discovery_client.h
deleted file mode 100644
index 7be433873..000000000
--- a/components/service/discovery/client/discovery_client.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef DISCOVERY_CLIENT_H
-#define DISCOVERY_CLIENT_H
-
-#include <psa/error.h>
-#include <service/common/client/service_client.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Get service info
- *
- * Discover service information from the service provider
- * instance associated with the provided service_client
- * object. If information is discovered, the service_client
- * object is updated with the discovered information.
- *
- * @param[in] service_client An initialized service client
- *
- * @return Success if information discovered
- */
-psa_status_t discovery_client_get_service_info(
- struct service_client *service_client);
-
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* DISCOVERY_CLIENT_H */
diff --git a/components/service/discovery/provider/discovery_info.h b/components/service/discovery/provider/discovery_info.h
deleted file mode 100644
index 2d46a5a11..000000000
--- a/components/service/discovery/provider/discovery_info.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef DISCOVERY_INFO_H
-#define DISCOVERY_INFO_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Information about the service deployment.
- */
-struct discovery_deployment_info
-{
- /**
- * The RPC interface id that should be used for directing call
- * requests to this service provider instance.
- */
- uint16_t interface_id;
-
- /**
- * The instance number assigned to this service provider instance.
- * This can be used by a client for identifying a particular instance
- * of a service provider for cases where multple instances of the same
- * type of service provider are deployed. The instance may be reflected
- * to clients using a standard convention such as a device numder
- * e.g. /dev/ps0 on Linux.
- */
- uint16_t instance;
-
- /**
- * When the discovery provider and associated service provider are
- * co-located (e.g. running in the same SP or TA), the max_payload
- * value reported by the discovery provider is determined from the
- * response buffer size associated with an incoming call_req object.
- * However in cases where call requests are forwarded, say to a
- * secure enclave, a different max_payload value may apply. This
- * value allows for a deployment specific override that will
- * be reported instead. Should be set to zero if no override
- * applies.
- */
- size_t max_payload_override;
-};
-
-/**
- * Aggregate of all discovery info
- */
-struct discovery_info
-{
- struct discovery_deployment_info deployment;
-
- uint32_t supported_encodings;
-};
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* DISCOVERY_INFO_H */
diff --git a/components/service/discovery/provider/discovery_provider.c b/components/service/discovery/provider/discovery_provider.c
deleted file mode 100644
index 2297d52ef..000000000
--- a/components/service/discovery/provider/discovery_provider.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-#include <protocols/service/discovery/packed-c/opcodes.h>
-#include <service/discovery/provider/discovery_provider.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <psa/error.h>
-
-/* Service request handlers */
-static rpc_status_t get_service_info_handler(void *context, struct call_req *req);
-static rpc_status_t get_provider_info_handler(void *context, struct call_req *req);
-static rpc_status_t get_service_caps_handler(void *context, struct call_req *req);
-
-/* Other private functions */
-static size_t determine_max_payload(
- const struct discovery_deployment_info *deployment_info,
- const struct call_req *req);
-
-/* Handler mapping table for service */
-static const struct service_handler handler_table[] = {
- {TS_DISCOVERY_OPCODE_GET_SERVICE_INFO, get_service_info_handler},
- {TS_DISCOVERY_OPCODE_GET_PROVIDER_INFO, get_provider_info_handler},
- {TS_DISCOVERY_OPCODE_GET_SERVICE_CAPS, get_service_caps_handler}
-};
-
-
-void discovery_provider_init(struct discovery_provider *context)
-{
- /* Initialise the base provider */
- for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
- context->serializers[encoding] = NULL;
-
- service_provider_init(&context->base_provider, context,
- handler_table, sizeof(handler_table)/sizeof(struct service_handler));
-
- /* Set default deployment settings. Deployment specific settings may be
- * applied using discovery_provider_set_deployment_info().
- */
- context->info.deployment.interface_id = 0;
- context->info.deployment.instance = 0;
- context->info.deployment.max_payload_override = 0;
-
- /* Bitmap is set when serializers are registered */
- context->info.supported_encodings = 0;
-}
-
-void discovery_provider_deinit(struct discovery_provider *context)
-{
- (void)context;
-}
-
-void discovery_provider_register_serializer(struct discovery_provider *context,
- unsigned int encoding, const struct discovery_provider_serializer *serializer)
-{
- if (encoding < TS_RPC_ENCODING_LIMIT)
- context->serializers[encoding] = serializer;
-}
-
-void discovery_provider_register_supported_encoding(
- struct discovery_provider *context,
- unsigned int encoding)
-{
- context->info.supported_encodings |= (1U << encoding);
-}
-
-void discovery_provider_set_deployment_info(
- struct discovery_provider *context,
- const struct discovery_deployment_info *deployment_info)
-{
- context->info.deployment = *deployment_info;
-}
-
-static const struct discovery_provider_serializer* get_discovery_serializer(void *context,
- const struct call_req *req)
-{
- struct discovery_provider *this_instance = (struct discovery_provider*)context;
- const struct discovery_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
-
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
-
- return serializer;
-}
-
-static rpc_status_t get_service_info_handler(void *context, struct call_req* req)
-{
- struct discovery_provider *this_instance = (struct discovery_provider*)context;
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- const struct discovery_provider_serializer *serializer = get_discovery_serializer(context, req);
-
- if (serializer) {
-
- size_t max_payload = determine_max_payload(&this_instance->info.deployment, req);
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-
- rpc_status = serializer->serialize_get_service_info_resp(resp_buf,
- max_payload,
- &this_instance->info);
-
- call_req_set_opstatus(req, PSA_SUCCESS);
- }
-
- return rpc_status;
-}
-
-static rpc_status_t get_provider_info_handler(void *context, struct call_req* req)
-{
- (void)context;
-
- call_req_set_opstatus(req, PSA_ERROR_NOT_SUPPORTED);
- return TS_RPC_CALL_ACCEPTED;
-}
-
-static rpc_status_t get_service_caps_handler(void *context, struct call_req* req)
-{
- (void)context;
-
- call_req_set_opstatus(req, PSA_ERROR_NOT_SUPPORTED);
- return TS_RPC_CALL_ACCEPTED;
-}
-
-static size_t determine_max_payload(
- const struct discovery_deployment_info *deployment_info,
- const struct call_req *req)
-{
- size_t max_payload;
-
- if (!deployment_info->max_payload_override) {
-
- /* No deployment specific override has been provided so
- * determine the maximum payload value from the call_req
- * buffer sizes. This will have been set by the
- * underlying RPC layer.
- */
- const struct call_param_buf *req_buf = &req->req_buf;
- const struct call_param_buf *resp_buf = &req->resp_buf;
-
- max_payload = (req_buf->size < resp_buf->size) ?
- req_buf->size :
- resp_buf->size;
- }
- else {
-
- /* A deployment specific override has been provided */
- max_payload = deployment_info->max_payload_override;
- }
-
- return max_payload;
-}
diff --git a/components/service/discovery/provider/discovery_provider.h b/components/service/discovery/provider/discovery_provider.h
deleted file mode 100644
index 298cef042..000000000
--- a/components/service/discovery/provider/discovery_provider.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef DISCOVERY_PROVIDER_H
-#define DISCOVERY_PROVIDER_H
-
-#include <stdint.h>
-#include <service/common/provider/service_provider.h>
-#include <service/discovery/provider/serializer/discovery_provider_serializer.h>
-#include <service/discovery/provider/discovery_info.h>
-#include <protocols/rpc/common/packed-c/encoding.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Instance data for a discover_provider object.
- */
-struct discovery_provider
-{
- struct service_provider base_provider;
- const struct discovery_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
-
- struct discovery_info info;
-};
-
-/**
- * Initializes an instance of the discovery service provider.
- */
-void discovery_provider_init(
- struct discovery_provider *context);
-
-/**
- * When operation of the provider is no longer required, this function
- * frees any resource used by the previously initialized provider instance.
- */
-void discovery_provider_deinit(
- struct discovery_provider *context);
-
-/**
- * Register a serializer for supportng a particular parameter encoding.
- */
-void discovery_provider_register_serializer(
- struct discovery_provider *context,
- unsigned int encoding,
- const struct discovery_provider_serializer *serializer);
-
-/**
- * Register a supported protocol encoding for the service provider that
- * this discovery provider represents.
- */
-void discovery_provider_register_supported_encoding(
- struct discovery_provider *context,
- unsigned int encoding);
-
-/**
- * Sets deployment specific information that is adverstised by the
- * discovery provider.
- */
-void discovery_provider_set_deployment_info(
- struct discovery_provider *context,
- const struct discovery_deployment_info *deployment_info);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* DISCOVERY_PROVIDER_H */
diff --git a/components/service/discovery/provider/serializer/discovery_provider_serializer.h b/components/service/discovery/provider/serializer/discovery_provider_serializer.h
deleted file mode 100644
index 89d166fd8..000000000
--- a/components/service/discovery/provider/serializer/discovery_provider_serializer.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef DISCOVERY_PROVIDER_SERIALIZER_H
-#define DISCOVERY_PROVIDER_SERIALIZER_H
-
-#include <stddef.h>
-#include <service/discovery/provider/discovery_info.h>
-#include <rpc/common/endpoint/rpc_interface.h>
-
-/* Provides a common interface for parameter serialization operations
- * for the discovery service provider. Allows alternative serialization
- * protocols to be used without hard-wiring a particular protocol
- * into the service provider code. A concrete serializer must
- * implement this interface.
- */
-struct discovery_provider_serializer {
-
- /* Operation: get_service_info */
- rpc_status_t (*serialize_get_service_info_resp)(struct call_param_buf *resp_buf,
- size_t max_payload,
- const struct discovery_info *info);
-};
-
-#endif /* DISCOVERY_PROVIDER_SERIALIZER_H */
diff --git a/components/service/discovery/provider/serializer/packed-c/component.cmake b/components/service/discovery/provider/serializer/packed-c/component.cmake
deleted file mode 100644
index 319f06242..000000000
--- a/components/service/discovery/provider/serializer/packed-c/component.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-if (NOT DEFINED TGT)
- message(FATAL_ERROR "mandatory parameter TGT is not defined.")
-endif()
-
-target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/packedc_discovery_provider_serializer.c"
- )
diff --git a/components/service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.c b/components/service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.c
deleted file mode 100644
index 5550ce737..000000000
--- a/components/service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-#include <string.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <protocols/service/discovery/packed-c/get_service_info.h>
-#include "packedc_discovery_provider_serializer.h"
-
-/* Operation: get_service_info */
-static rpc_status_t serialize_get_service_info_resp(struct call_param_buf *resp_buf,
- size_t max_payload,
- const struct discovery_info *info)
-{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
- struct ts_discovery_get_service_info_out resp_msg;
- size_t fixed_len = sizeof(struct ts_discovery_get_service_info_out);
-
- resp_msg.instance = info->deployment.instance;
- resp_msg.interface_id = info->deployment.interface_id;
-
- resp_msg.max_payload = max_payload;
- resp_msg.supported_encodings = info->supported_encodings;
-
- if (fixed_len <= resp_buf->size) {
-
- memcpy(resp_buf->data, &resp_msg, fixed_len);
- resp_buf->data_len = fixed_len;
-
- rpc_status = TS_RPC_CALL_ACCEPTED;
- }
-
- return rpc_status;
-}
-
-/* Singleton method to provide access to the serializer instance */
-const struct discovery_provider_serializer *packedc_discovery_provider_serializer_instance(void)
-{
- static const struct discovery_provider_serializer instance =
- {
- serialize_get_service_info_resp
- };
-
- return &instance;
-}
diff --git a/components/service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.h b/components/service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.h
deleted file mode 100644
index 8bfd68a0b..000000000
--- a/components/service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef PACKEDC_DISCOVERY_PROVIDER_SERIALIZER_H
-#define PACKEDC_DISCOVERY_PROVIDER_SERIALIZER_H
-
-#include <service/discovery/provider/serializer/discovery_provider_serializer.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Singleton method to provide access to the packed-c serializer
- * for the discovery service provider.
- */
-const struct discovery_provider_serializer *packedc_discovery_provider_serializer_instance(void);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* PACKEDC_DISCOVERY_PROVIDER_SERIALIZER_H */
diff --git a/components/service/discovery/test/service/component.cmake b/components/service/discovery/test/service/component.cmake
deleted file mode 100644
index 7f8a18ae4..000000000
--- a/components/service/discovery/test/service/component.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-if (NOT DEFINED TGT)
- message(FATAL_ERROR "mandatory parameter TGT is not defined.")
-endif()
-
-target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/discovery_service_tests.cpp"
- )
diff --git a/components/service/discovery/test/service/discovery_service_tests.cpp b/components/service/discovery/test/service/discovery_service_tests.cpp
deleted file mode 100644
index 654986ef1..000000000
--- a/components/service/discovery/test/service/discovery_service_tests.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <service/discovery/client/discovery_client.h>
-#include <protocols/rpc/common/packed-c/encoding.h>
-#include <service_locator.h>
-#include <CppUTest/TestHarness.h>
-
-/*
- * Service-level tests for the discovery service. The discovery service
- * provides common operations that may be called at all service endpoints.
- * These tests use the crypto service as the target.
- */
-TEST_GROUP(DiscoveryServiceTests)
-{
- void setup()
- {
- int status;
-
- m_rpc_session_handle = NULL;
- m_service_context = NULL;
-
- service_locator_init();
-
- m_service_context =
- service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
- CHECK_TRUE(m_service_context);
-
- m_rpc_session_handle =
- service_context_open(m_service_context, TS_RPC_ENCODING_PACKED_C, &m_caller);
- CHECK_TRUE(m_rpc_session_handle);
- }
-
- void teardown()
- {
- service_context_close(m_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
-
- service_context_relinquish(m_service_context);
- m_service_context = NULL;
- }
-
- struct rpc_caller *m_caller;
- rpc_session_handle m_rpc_session_handle;
- struct service_context *m_service_context;
-};
-
-TEST(DiscoveryServiceTests, checkServiceInfo)
-{
- struct service_client service_client;
- psa_status_t status;
-
- status = service_client_init(&service_client, m_caller);
- LONGS_EQUAL(PSA_SUCCESS, status);
-
- status = discovery_client_get_service_info(&service_client);
- LONGS_EQUAL(PSA_SUCCESS, status);
-
- /* Check discovered service info looks reasonable */
- CHECK_TRUE(service_client.service_info.max_payload);
- CHECK_TRUE(service_client.service_info.supported_encodings);
-}
diff --git a/components/service/fwu/agent/component.cmake b/components/service/fwu/agent/component.cmake
new file mode 100644
index 000000000..f5dddc681
--- /dev/null
+++ b/components/service/fwu/agent/component.cmake
@@ -0,0 +1,16 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fw_directory.c"
+ "${CMAKE_CURRENT_LIST_DIR}/update_agent.c"
+ "${CMAKE_CURRENT_LIST_DIR}/stream_manager.c"
+ "${CMAKE_CURRENT_LIST_DIR}/img_dir_serializer.c"
+ )
diff --git a/components/service/fwu/agent/fw_directory.c b/components/service/fwu/agent/fw_directory.c
new file mode 100644
index 000000000..ec7486bc8
--- /dev/null
+++ b/components/service/fwu/agent/fw_directory.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "fw_directory.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "protocols/service/fwu/packed-c/status.h"
+
+void fw_directory_init(struct fw_directory *fw_directory)
+{
+ assert(fw_directory);
+
+ /* The fw_directory is initially empty. It will be populated by a
+ * fw_inspector.
+ */
+ memset(fw_directory, 0, sizeof(struct fw_directory));
+}
+
+void fw_directory_deinit(struct fw_directory *fw_directory)
+{
+ (void)fw_directory;
+}
+
+void fw_directory_set_boot_info(struct fw_directory *fw_directory,
+ const struct boot_info *boot_info)
+{
+ assert(fw_directory);
+ fw_directory->boot_info = *boot_info;
+}
+
+int fw_directory_add_image_info(struct fw_directory *fw_directory,
+ const struct image_info *image_info)
+{
+ assert(fw_directory);
+ assert(image_info);
+
+ int status = FWU_STATUS_UNKNOWN;
+
+ if (fw_directory->num_images < FWU_MAX_FW_DIRECTORY_ENTRIES) {
+ uint32_t image_index = fw_directory->num_images;
+
+ fw_directory->entries[image_index] = *image_info;
+ fw_directory->entries[image_index].image_index = image_index;
+
+ ++fw_directory->num_images;
+
+ status = FWU_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+const struct image_info *fw_directory_find_image_info(const struct fw_directory *fw_directory,
+ const struct uuid_octets *img_type_uuid)
+{
+ assert(fw_directory);
+ assert(img_type_uuid);
+
+ const struct image_info *info = NULL;
+
+ for (size_t i = 0; i < fw_directory->num_images; i++) {
+ if (uuid_is_equal(img_type_uuid->octets,
+ fw_directory->entries[i].img_type_uuid.octets)) {
+ info = &fw_directory->entries[i];
+ break;
+ }
+ }
+
+ return info;
+}
+
+const struct boot_info *fw_directory_get_boot_info(const struct fw_directory *fw_directory)
+{
+ assert(fw_directory);
+ return &fw_directory->boot_info;
+}
+
+const struct image_info *fw_directory_get_image_info(const struct fw_directory *fw_directory,
+ size_t index)
+{
+ assert(fw_directory);
+
+ const struct image_info *info = NULL;
+
+ if (index < fw_directory->num_images)
+ info = &fw_directory->entries[index];
+
+ return info;
+}
+
+size_t fw_directory_num_images(const struct fw_directory *fw_directory)
+{
+ assert(fw_directory);
+ return fw_directory->num_images;
+}
diff --git a/components/service/fwu/agent/fw_directory.h b/components/service/fwu/agent/fw_directory.h
new file mode 100644
index 000000000..6c59554d9
--- /dev/null
+++ b/components/service/fwu/agent/fw_directory.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FW_DIRECTORY_H
+#define FW_DIRECTORY_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "common/uuid/uuid.h"
+#include "install_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The default maximum number of images that can be held by the fw_directory.
+ * Can be overridden by an external definition.
+ */
+#ifndef FWU_MAX_FW_DIRECTORY_ENTRIES
+#define FWU_MAX_FW_DIRECTORY_ENTRIES (20)
+#endif
+
+/**
+ * \brief Boot information structure definition
+ *
+ * The boot_info structure holds information obtained from the boot loader
+ * about the most recent boot.
+ */
+struct boot_info {
+ /* Identifies the bank that was used during boot */
+ uint32_t boot_index;
+
+ /* The state of the active_index metadata variable during boot */
+ uint32_t active_index;
+
+ /* The state of the previous_active_index metadata variable during boot */
+ uint32_t previous_active_index;
+};
+
+/**
+ * \brief Image information structure definition
+ *
+ * Information about an updatable image. Firmware may consist of an arbitrary
+ * number of images that may be updated as a single unit. Images may correspond
+ * to individual components, such as the Crypto SP image, or a collection of
+ * components contained within a package understood by firmware such as a FIP.
+ */
+struct image_info {
+ /* Unique identifier for the image type. This corresponds to the UUID/GUID
+ * assigned by the originator of the update package to identify the image.
+ */
+ struct uuid_octets img_type_uuid;
+
+ /* The maximum size that can be accommodated for an image of this type.
+ * A platform integrator will have sized back-end storage to provide
+ * sufficient headroom to accommodate updates.
+ */
+ size_t max_size;
+
+ /* The lowest accepted version number for this image. This will correspond
+ * to the NV anti-rollback counter value associated with the image.
+ */
+ uint32_t lowest_accepted_version;
+
+ /* The version of the currently active version of this image. */
+ uint32_t active_version;
+
+ /* Bitmap of access permissions for this image. */
+ uint32_t permissions;
+
+ /* The index [0..n] of the image in the fw directory. */
+ uint32_t image_index;
+
+ /* The location_id assigned by the platform integrator. A fw_store may
+ * be distributed over multiple locations (e.g. different storage partitions).
+ * The location_id is used to associate installers to storage volumes.
+ */
+ uint32_t location_id;
+
+ /* Identifies the type of installation needed for the image. */
+ enum install_type install_type;
+};
+
+/**
+ * \brief Firmware directory structure definition
+ *
+ * The fw_directory holds information about currently active firmware. Information
+ * will have been collected via a trusted pathway. A subset of the information held
+ * is presented to external clients.
+ */
+struct fw_directory {
+ struct boot_info boot_info;
+ size_t num_images;
+ struct image_info entries[FWU_MAX_FW_DIRECTORY_ENTRIES];
+};
+
+/**
+ * \brief Initialise a fw_directory
+ *
+ * Initialises the subject fw_directory. After initialisation, the empty fw_directory
+ * will need to be populated by a trusted agent (the fw_inspector).
+ *
+ * \param[in] fw_directory The subject fw_directory
+ */
+void fw_directory_init(struct fw_directory *fw_directory);
+
+/**
+ * \brief De-initialise a fw_directory
+ *
+ * \param[in] fw_directory The subject fw_directory
+ */
+void fw_directory_deinit(struct fw_directory *fw_directory);
+
+/**
+ * \brief Sets the boot_info held by the fw_directory
+ *
+ * Used by a fw_inspector to set the boot_info for the most recent system boot.
+ *
+ * \param[in] fw_directory The subject fw_directory
+ * \param[in] boot_info boot_info for most recent system boot
+ */
+void fw_directory_set_boot_info(struct fw_directory *fw_directory,
+ const struct boot_info *boot_info);
+
+/**
+ * \brief Adds an image_info to the directory
+ *
+ * Used by a fw_inspector to add an image_info entry to the directory.
+ *
+ * \param[in] fw_directory The subject fw_directory
+ * \param[in] image_info The entry to add
+ *
+ * \return FWU status
+ */
+int fw_directory_add_image_info(struct fw_directory *fw_directory,
+ const struct image_info *image_info);
+
+/**
+ * \brief Find an image_info entry
+ *
+ * Query to find an image_info entry using the image type UUID as the key.
+ *
+ * \param[in] fw_directory The subject fw_directory
+ * \param[in] image_type_uuid Image type UUID
+ *
+ * \return Pointer to image_info or NULL
+ */
+const struct image_info *fw_directory_find_image_info(const struct fw_directory *fw_directory,
+ const struct uuid_octets *img_type_uuid);
+
+/**
+ * \brief Get the boot_info
+ *
+ * \param[in] fw_directory The subject fw_directory
+ *
+ * \return Pointer to the boot_info
+ */
+const struct boot_info *fw_directory_get_boot_info(const struct fw_directory *fw_directory);
+
+/**
+ * \brief Get an image_info by index
+ *
+ * Can be used for iterating over all image_info objects held.
+ *
+ * \param[in] fw_directory The subject fw_directory
+ * \param[in] index Index in range [0..num_images-1]
+ *
+ * \return Pointer to the image_info or NULL if index invalid
+ */
+const struct image_info *fw_directory_get_image_info(const struct fw_directory *fw_directory,
+ size_t index);
+
+/**
+ * \brief Get the number of image_info entries held
+ *
+ * \param[in] fw_directory The subject fw_directory
+ *
+ * \return Number of entries
+ */
+size_t fw_directory_num_images(const struct fw_directory *fw_directory);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FW_DIRECTORY_H */
diff --git a/components/service/fwu/agent/img_dir_serializer.c b/components/service/fwu/agent/img_dir_serializer.c
new file mode 100644
index 000000000..d1f44afd5
--- /dev/null
+++ b/components/service/fwu/agent/img_dir_serializer.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "img_dir_serializer.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "fw_directory.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+#include "service/fwu/fw_store/fw_store.h"
+
+int img_dir_serializer_serialize(const struct fw_directory *fw_dir, const struct fw_store *fw_store,
+ uint8_t *buf, size_t buf_size, size_t *data_len)
+{
+ size_t serialized_len = img_dir_serializer_get_len(fw_dir);
+
+ *data_len = 0;
+
+ if (buf_size < serialized_len)
+ return FWU_STATUS_OUT_OF_BOUNDS;
+
+ struct ts_fwu_image_directory *output = (struct ts_fwu_image_directory *)buf;
+
+ /* Clear the output buffer */
+ memset(buf, 0, serialized_len);
+
+ /* Serialize boot info */
+ const struct boot_info *boot_info = fw_directory_get_boot_info(fw_dir);
+
+ assert(boot_info);
+
+ output->directory_version = 2;
+ output->img_info_offset = offsetof(struct ts_fwu_image_directory, img_info_entry);
+ output->num_images = fw_directory_num_images(fw_dir);
+ output->correct_boot = (boot_info->active_index == boot_info->boot_index);
+ output->img_info_size = sizeof(struct ts_fwu_image_info_entry);
+ output->reserved = 0;
+
+ /* Serialize image info for each image */
+ for (size_t image_index = 0; image_index < output->num_images; image_index++) {
+ const struct image_info *image_info =
+ fw_directory_get_image_info(fw_dir, image_index);
+
+ assert(image_info);
+
+ memcpy(output->img_info_entry[image_index].img_type_uuid,
+ image_info->img_type_uuid.octets, OSF_UUID_OCTET_LEN);
+
+ output->img_info_entry[image_index].client_permissions = image_info->permissions;
+ output->img_info_entry[image_index].img_max_size = image_info->max_size;
+ output->img_info_entry[image_index].lowest_accepted_version =
+ image_info->lowest_accepted_version;
+ output->img_info_entry[image_index].img_version = image_info->active_version;
+ output->img_info_entry[image_index].accepted =
+ (uint32_t)fw_store_is_accepted(fw_store, image_info);
+ }
+
+ *data_len = serialized_len;
+
+ return FWU_STATUS_SUCCESS;
+}
+
+size_t img_dir_serializer_get_len(const struct fw_directory *fw_dir)
+{
+ return offsetof(struct ts_fwu_image_directory, img_info_entry) +
+ sizeof(struct ts_fwu_image_info_entry) * fw_directory_num_images(fw_dir);
+}
diff --git a/components/service/fwu/agent/img_dir_serializer.h b/components/service/fwu/agent/img_dir_serializer.h
new file mode 100644
index 000000000..fe8c7ec1b
--- /dev/null
+++ b/components/service/fwu/agent/img_dir_serializer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef IMG_DIR_SERIALIZER_H
+#define IMG_DIR_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct fw_directory;
+struct fw_store;
+
+/**
+ * \brief Serialize the public image directory
+ *
+ * Using content from the internal fw_directory and fw_store, create
+ * a serialized image_directory that conforms to the FWU-A specification
+ * format.
+ *
+ * \param[in] fw_dir Source fw_directory
+ * \param[in] fw_store Source fw_store
+ * \param[in] buf Serialize into this buffer
+ * \param[in] buf_size Size of buffer
+ * \param[out] data_len Length of serialized data
+ *
+ * \return Status
+ */
+int img_dir_serializer_serialize(const struct fw_directory *fw_dir, const struct fw_store *fw_store,
+ uint8_t *buf, size_t buf_size, size_t *data_len);
+
+/**
+ * \brief Return the length in bytes of the serialized image directory
+ *
+ * \param[in] fw_dir Source fw_directory
+ *
+ * \return Size in bytes
+ */
+size_t img_dir_serializer_get_len(const struct fw_directory *fw_dir);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IMG_DIR_SERIALIZER_H */
diff --git a/components/service/fwu/agent/install_type.h b/components/service/fwu/agent/install_type.h
new file mode 100644
index 000000000..dc72fbfe3
--- /dev/null
+++ b/components/service/fwu/agent/install_type.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef INSTALL_TYPE_H
+#define INSTALL_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief A classifier for the type of installation performed by an installer
+ *
+ * The scope of an update image may encompass the whole contents of a storage
+ * volume or just a part of the volume. The install_type is used to help
+ * associate an incoming image with an appropriate installer.
+ */
+enum install_type {
+
+ /* An installer that updates the entire contents of a storage volume.
+ * This type of installer doesn't need to understand the installed
+ * image format and can just install directly into a storage volume.
+ */
+ INSTALL_TYPE_WHOLE_VOLUME,
+
+ /* An installer that updates a part of a storage volume. To achieve
+ * this, the installer must have knowledge of the format of the target
+ * storage volume.
+ */
+ INSTALL_TYPE_SUB_VOLUME,
+
+ /* An installer that copies the entire contents of one volume to
+ * another. No externally provided update data is installed. When
+ * a platform with multiple locations receives an update that only
+ * updates some locations, a whole volume copy installer can be used
+ * to duplicate the active bank contents into the update bank.
+ */
+ INSTALL_TYPE_WHOLE_VOLUME_COPY,
+
+ INSTALL_TYPE_LIMIT
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INSTALL_TYPE_H */
diff --git a/components/service/fwu/agent/stream_manager.c b/components/service/fwu/agent/stream_manager.c
new file mode 100644
index 000000000..c93bdf1b4
--- /dev/null
+++ b/components/service/fwu/agent/stream_manager.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "stream_manager.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/fw_store/fw_store.h"
+
+static uint32_t generate_handle(struct stream_manager *subject,
+ const struct stream_context *const context)
+{
+ /* Handle includes rolling count value to protect against use of a stale handle */
+ uint32_t new_handle = context - subject->contexts;
+
+ new_handle = (new_handle & 0xffff) | (subject->rolling_count << 16);
+ ++subject->rolling_count;
+ return new_handle;
+}
+
+static uint32_t index_from_handle(uint32_t handle)
+{
+ return handle & 0xffff;
+}
+
+static void add_to_free_list(struct stream_manager *subject, struct stream_context *context)
+{
+ context->type = FWU_STREAM_TYPE_NONE;
+ context->handle = 0;
+ context->next = subject->free;
+ context->prev = NULL;
+ subject->free = context;
+}
+
+static struct stream_context *alloc_stream_context(struct stream_manager *subject,
+ enum fwu_stream_type type, uint32_t *handle)
+{
+ struct stream_context *context = NULL;
+
+ /* Re-cycle least-recently used context if there are no free contexts */
+ if (!subject->free && subject->active_tail) {
+ stream_manager_close(subject, subject->active_tail->handle, false);
+ }
+
+ /* Active contexts are held in a linked list in most recently allocated order */
+ if (subject->free) {
+ context = subject->free;
+ subject->free = context->next;
+
+ context->next = subject->active_head;
+ context->prev = NULL;
+ subject->active_head = context;
+
+ if (!subject->active_tail)
+ subject->active_tail = context;
+
+ if (context->next)
+ context->next->prev = context;
+
+ context->type = type;
+
+ context->handle = generate_handle(subject, context);
+ *handle = context->handle;
+ }
+
+ return context;
+}
+
+static void free_stream_context(struct stream_manager *subject, struct stream_context *context)
+{
+ /* Remove from active list */
+ if (context->prev)
+ context->prev->next = context->next;
+ else
+ subject->active_head = context->next;
+
+ if (context->next)
+ context->next->prev = context->prev;
+ else
+ subject->active_tail = context->prev;
+
+ /* Add to free list */
+ add_to_free_list(subject, context);
+}
+
+static struct stream_context *get_active_context(struct stream_manager *subject, uint32_t handle)
+{
+ struct stream_context *context = NULL;
+ uint32_t index = index_from_handle(handle);
+
+ if ((index < FWU_STREAM_MANAGER_POOL_SIZE) &&
+ (subject->contexts[index].type != FWU_STREAM_TYPE_NONE) &&
+ (subject->contexts[index].handle == handle)) {
+ /* Handle qualifies an active stream context */
+ context = &subject->contexts[index];
+ }
+
+ return context;
+}
+
+void stream_manager_init(struct stream_manager *subject)
+{
+ subject->free = NULL;
+ subject->active_head = NULL;
+ subject->active_tail = NULL;
+ subject->rolling_count = 0;
+
+ for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++)
+ add_to_free_list(subject, &subject->contexts[i]);
+}
+
+void stream_manager_deinit(struct stream_manager *subject)
+{
+ (void)subject;
+}
+
+int stream_manager_open_buffer_stream(struct stream_manager *subject, const uint8_t *data,
+ size_t data_len, uint32_t *handle)
+{
+ struct stream_context *context;
+ int status = FWU_STATUS_UNKNOWN;
+
+ /* First cancel any buffer streams left open associated with
+ * the same source buffer. Concurrent stream access to data in
+ * a buffer is prevented to avoid the possibility of a buffer
+ * being updated while a read stream is open.
+ */
+ for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++) {
+ context = &subject->contexts[i];
+
+ if ((context->type == FWU_STREAM_TYPE_BUFFER) &&
+ (context->variant.buffer.data == data))
+ free_stream_context(subject, context);
+ }
+
+ /* Allocate and initialize a new stream */
+ context = alloc_stream_context(subject, FWU_STREAM_TYPE_BUFFER, handle);
+
+ if (context) {
+ context->variant.buffer.data = data;
+ context->variant.buffer.data_len = data_len;
+ context->variant.buffer.pos = 0;
+
+ status = FWU_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+int stream_manager_open_install_stream(struct stream_manager *subject, struct fw_store *fw_store,
+ struct installer *installer,
+ const struct image_info *image_info, uint32_t *stream_handle)
+{
+ struct stream_context *context;
+ int status = FWU_STATUS_UNKNOWN;
+
+ /* First cancel any install streams left open associated with
+ * the same fw_store and installer. This defends against the
+ * possibility of data written via two streams being written to the
+ * same installer, resulting in image corruption.
+ */
+ for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++) {
+ context = &subject->contexts[i];
+
+ if ((context->type == FWU_STREAM_TYPE_INSTALL) &&
+ (context->variant.install.fw_store == fw_store) &&
+ (context->variant.install.installer == installer))
+ free_stream_context(subject, context);
+ }
+
+ /* Allocate and initialize a new stream */
+ context = alloc_stream_context(subject, FWU_STREAM_TYPE_INSTALL, stream_handle);
+
+ if (context) {
+ context->variant.install.fw_store = fw_store;
+ context->variant.install.installer = installer;
+ context->variant.install.image_info = image_info;
+
+ status = FWU_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+int stream_manager_close(struct stream_manager *subject, uint32_t handle, bool accepted)
+{
+ int status = FWU_STATUS_UNKNOWN;
+ struct stream_context *context = get_active_context(subject, handle);
+
+ if (context) {
+ status = FWU_STATUS_SUCCESS;
+
+ if (context->type == FWU_STREAM_TYPE_INSTALL) {
+ status = fw_store_commit_image(context->variant.install.fw_store,
+ context->variant.install.installer,
+ context->variant.install.image_info,
+ accepted);
+ }
+
+ free_stream_context(subject, context);
+ }
+
+ return status;
+}
+
+void stream_manager_cancel_streams(struct stream_manager *subject, enum fwu_stream_type type)
+{
+ for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++) {
+ struct stream_context *context = &subject->contexts[i];
+
+ if (context->type == type)
+ free_stream_context(subject, context);
+ }
+}
+
+bool stream_manager_is_open_streams(const struct stream_manager *subject, enum fwu_stream_type type)
+{
+ bool any_open = false;
+
+ for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++) {
+ const struct stream_context *context = &subject->contexts[i];
+
+ if (context->type == type) {
+ any_open = true;
+ break;
+ }
+ }
+
+ return any_open;
+}
+
+int stream_manager_write(struct stream_manager *subject, uint32_t handle, const uint8_t *data,
+ size_t data_len)
+{
+ int status = FWU_STATUS_UNKNOWN;
+ struct stream_context *context = get_active_context(subject, handle);
+
+ if (context && context->type == FWU_STREAM_TYPE_INSTALL) {
+ status = fw_store_write_image(context->variant.install.fw_store,
+ context->variant.install.installer, data, data_len);
+ }
+
+ return status;
+}
+
+int stream_manager_read(struct stream_manager *subject, uint32_t handle, uint8_t *buf,
+ size_t buf_size, size_t *read_len, size_t *total_len)
+{
+ int status = FWU_STATUS_UNKNOWN;
+ struct stream_context *context = get_active_context(subject, handle);
+
+ if (context) {
+ if (context->type == FWU_STREAM_TYPE_BUFFER) {
+ size_t pos = context->variant.buffer.pos;
+ size_t remaining_len = context->variant.buffer.data_len - pos;
+ size_t len_to_read = (remaining_len <= buf_size) ? remaining_len : buf_size;
+
+ memcpy(buf, &context->variant.buffer.data[pos], len_to_read);
+
+ *read_len = len_to_read;
+ *total_len = context->variant.buffer.data_len;
+ context->variant.buffer.pos = pos + len_to_read;
+
+ status = FWU_STATUS_SUCCESS;
+ } else {
+ /* Reading from other types of stream is forbidden */
+ status = FWU_STATUS_DENIED;
+ }
+ }
+
+ return status;
+}
diff --git a/components/service/fwu/agent/stream_manager.h b/components/service/fwu/agent/stream_manager.h
new file mode 100644
index 000000000..0ce534d62
--- /dev/null
+++ b/components/service/fwu/agent/stream_manager.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_STREAM_MANAGER_H
+#define FWU_STREAM_MANAGER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * Manages the set of streams used by the update_agent for image installation
+ * and accessing other FWU related objects. A subject of stream objects is managed
+ * to allow for concurrent streams if needed. To defend against a badly behaved
+ * client that fails to close streams, if necessary, the least recently used
+ * open stream will be reused if necessary to prevent a denial of service attack
+ * where a rogue client opens streams but doesn't close them.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct fw_store;
+struct installer;
+struct image_info;
+
+/**
+ * The default stream subject size
+ */
+#ifndef FWU_STREAM_MANAGER_POOL_SIZE
+#define FWU_STREAM_MANAGER_POOL_SIZE (4)
+#endif
+
+/**
+ * Identifier for the type of stream
+ */
+enum fwu_stream_type { FWU_STREAM_TYPE_NONE, FWU_STREAM_TYPE_BUFFER, FWU_STREAM_TYPE_INSTALL };
+
+/**
+ * A stream context
+ */
+struct stream_context {
+ enum fwu_stream_type type;
+ uint32_t handle;
+ struct stream_context *next;
+ struct stream_context *prev;
+
+ union stream_variant {
+ /* Buffer stream variant */
+ struct buffer_variant {
+ size_t pos;
+ const uint8_t *data;
+ size_t data_len;
+
+ } buffer;
+
+ /* Install stream variant */
+ struct install_variant {
+ struct fw_store *fw_store;
+ struct installer *installer;
+ const struct image_info *image_info;
+
+ } install;
+
+ } variant;
+};
+
+/**
+ * The stream_manager structure.
+ */
+struct stream_manager {
+ struct stream_context contexts[FWU_STREAM_MANAGER_POOL_SIZE];
+ struct stream_context *free;
+ struct stream_context *active_head;
+ struct stream_context *active_tail;
+ uint16_t rolling_count;
+};
+
+/**
+ * \brief One-time initialization
+ *
+ * \param[in] subject The subject stream_manager
+ */
+void stream_manager_init(struct stream_manager *subject);
+
+/**
+ * \brief De-initializes a stream_manager
+ *
+ * \param[in] subject The subject stream_manager
+ */
+void stream_manager_deinit(struct stream_manager *subject);
+
+/**
+ * \brief Open a buffer stream
+ *
+ * Opens a stream for reading from a buffer containing the complete object
+ * to access.
+ *
+ * \param[in] subject The subject stream_manager
+ * \param[in] data Pointer to the buffer containing data
+ * \param[in] data_len The length of the data
+ * \param[out] stream_handle The stream handle to use for subsequent operations
+ *
+ * \return FWU status
+ */
+int stream_manager_open_buffer_stream(struct stream_manager *subject, const uint8_t *data,
+ size_t data_len, uint32_t *stream_handle);
+
+/**
+ * \brief Open an install stream
+ *
+ * Open a stream for writing an image to an installer. A concrete installer
+ * is responsible for installing the image into storage.
+ *
+ * \param[in] subject The subject stream_manager
+ * \param[in] fw_store The image_info for the image to install
+ * \param[in] installer The installer
+ * \param[in] image_info The image_info corresponding to the image to install
+ * \param[out] stream_handle The stream_handle to use for subsequent operations
+ *
+ * \return FWU status
+ */
+int stream_manager_open_install_stream(struct stream_manager *subject, struct fw_store *fw_store,
+ struct installer *installer,
+ const struct image_info *image_info,
+ uint32_t *stream_handle);
+
+/**
+ * \brief Close a previously opened stream
+ *
+ * \param[in] subject The subject stream_manager
+ * \param[in] stream_handle Stream handle
+ * \param[in] accepted The initial accepted state for an installed image
+ *
+ * \return FWU status
+ */
+int stream_manager_close(struct stream_manager *subject, uint32_t stream_handle, bool accepted);
+
+/**
+ * \brief Cancel all streams of the specified type
+ *
+ * \param[in] subject The subject stream_manager
+ * \param[in] type Type of stream to cancel
+ */
+void stream_manager_cancel_streams(struct stream_manager *subject, enum fwu_stream_type type);
+
+/**
+ * \brief Check for any open streams of the specified type
+ *
+ * \param[in] subject The subject stream_manager
+ * \param[in] type Type of stream to check
+ *
+ * \return True is any are open
+ */
+bool stream_manager_is_open_streams(const struct stream_manager *subject,
+ enum fwu_stream_type type);
+
+/**
+ * \brief Write to a previously opened stream
+ *
+ * \param[in] subject The subject stream_manager
+ * \param[in] stream_handle The handle returned by open
+ * \param[in] data Pointer to data
+ * \param[in] data_len The data length
+ *
+ * \return Status (0 on success)
+ */
+int stream_manager_write(struct stream_manager *subject, uint32_t stream_handle,
+ const uint8_t *data, size_t data_len);
+
+/**
+ * \brief Read from a previously opened stream
+ *
+ * \param[in] subject The subject stream_manager
+ * \param[in] stream_handle The handle returned by open
+ * \param[in] buf Pointer to buffer to copy to
+ * \param[in] buf_size The size of the buffer
+ * \param[out] read_len The length of data read
+ * \param[out] total_len The total length of object to read
+ *
+ * \return Status (0 on success)
+ */
+int stream_manager_read(struct stream_manager *subject, uint32_t handle, uint8_t *buf,
+ size_t buf_size, size_t *read_len, size_t *total_len);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FWU_STREAM_MANAGER_H */
diff --git a/components/service/fwu/agent/update_agent.c b/components/service/fwu/agent/update_agent.c
new file mode 100644
index 000000000..2a4d19d99
--- /dev/null
+++ b/components/service/fwu/agent/update_agent.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "update_agent.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/uuid/uuid.h"
+#include "img_dir_serializer.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/fw_store/fw_store.h"
+#include "service/fwu/inspector/fw_inspector.h"
+
+static bool open_image_directory(struct update_agent *update_agent, const struct uuid_octets *uuid,
+ uint32_t *handle, int *status);
+
+static bool open_fw_store_object(struct update_agent *update_agent, const struct uuid_octets *uuid,
+ uint32_t *handle, int *status);
+
+static bool open_fw_image(struct update_agent *update_agent, const struct uuid_octets *uuid,
+ uint32_t *handle, int *status);
+
+int update_agent_init(struct update_agent *update_agent, unsigned int boot_index,
+ fw_inspector_inspect fw_inspect_method, struct fw_store *fw_store)
+{
+ assert(update_agent);
+ assert(fw_inspect_method);
+ assert(fw_store);
+
+ int status = FWU_STATUS_UNKNOWN;
+
+ update_agent->state = FWU_STATE_INITIALIZING;
+ update_agent->fw_inspect_method = fw_inspect_method;
+ update_agent->fw_store = fw_store;
+ update_agent->image_dir_buf_size = 0;
+ update_agent->image_dir_buf = NULL;
+
+ stream_manager_init(&update_agent->stream_manager);
+
+ /* Initialize and populate the fw_directory. The fw_inspector will
+ * obtain trustworthy information about the booted firmware and
+ * populate the fw_directory to reflect information about the booted
+ * firmware.
+ */
+ fw_directory_init(&update_agent->fw_directory);
+
+ status = update_agent->fw_inspect_method(&update_agent->fw_directory, boot_index);
+ if (status != FWU_STATUS_SUCCESS)
+ return status;
+
+ /* Allow the associated fw_store to synchronize its state to the
+ * state of the booted firmware reflected by the fw_directory.
+ */
+ status = fw_store_synchronize(update_agent->fw_store, &update_agent->fw_directory,
+ boot_index);
+ if (status != FWU_STATUS_SUCCESS)
+ return status;
+
+ /* Allocate a buffer for holding the serialized image directory */
+ update_agent->image_dir_buf_size = img_dir_serializer_get_len(&update_agent->fw_directory);
+ update_agent->image_dir_buf = malloc(update_agent->image_dir_buf_size);
+ if (!update_agent->image_dir_buf)
+ return FWU_STATUS_UNKNOWN;
+
+ /* Transition to initial state */
+ update_agent->state = fw_store_is_trial(update_agent->fw_store) ? FWU_STATE_TRIAL :
+ FWU_STATE_REGULAR;
+
+ return FWU_STATUS_SUCCESS;
+}
+
+void update_agent_deinit(struct update_agent *update_agent)
+{
+ update_agent->state = FWU_STATE_DEINITIALZED;
+
+ free(update_agent->image_dir_buf);
+ fw_directory_deinit(&update_agent->fw_directory);
+ stream_manager_deinit(&update_agent->stream_manager);
+}
+
+int update_agent_begin_staging(struct update_agent *update_agent)
+{
+ int status = FWU_STATUS_DENIED;
+
+ /* If already staging, any previous installation state is discarded */
+ update_agent_cancel_staging(update_agent);
+
+ if (update_agent->state == FWU_STATE_REGULAR) {
+ status = fw_store_begin_install(update_agent->fw_store);
+
+ /* Check if ready to install images */
+ if (status == FWU_STATUS_SUCCESS)
+ update_agent->state = FWU_STATE_STAGING;
+ }
+
+ return status;
+}
+
+int update_agent_end_staging(struct update_agent *update_agent)
+{
+ int status = FWU_STATUS_DENIED;
+
+ if (update_agent->state == FWU_STATE_STAGING) {
+ /* The client is responsible for committing each installed image. If any
+ * install streams have been left open, not all images were committed.
+ */
+ bool any_uncommitted = stream_manager_is_open_streams(&update_agent->stream_manager,
+ FWU_STREAM_TYPE_INSTALL);
+
+ if (!any_uncommitted) {
+ /* All installed images have been committed so we're
+ * ready for a trial.
+ */
+ status = fw_store_finalize_install(update_agent->fw_store);
+
+ if (status == FWU_STATUS_SUCCESS)
+ /* Transition to TRAIL_PENDING state. The trial actually starts
+ * when installed images are activated through a system restart.
+ */
+ update_agent->state = FWU_STATE_TRIAL_PENDING;
+
+ } else {
+ /* Client failed to commit all images installed */
+ status = FWU_STATUS_BUSY;
+ }
+ }
+
+ return status;
+}
+
+int update_agent_cancel_staging(struct update_agent *update_agent)
+{
+ int status = FWU_STATUS_DENIED;
+
+ if (update_agent->state == FWU_STATE_STAGING) {
+ stream_manager_cancel_streams(&update_agent->stream_manager,
+ FWU_STREAM_TYPE_INSTALL);
+
+ fw_store_cancel_install(update_agent->fw_store);
+
+ update_agent->state = FWU_STATE_REGULAR;
+
+ status = FWU_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+int update_agent_accept(struct update_agent *update_agent,
+ const struct uuid_octets *image_type_uuid)
+{
+ int status = FWU_STATUS_DENIED;
+
+ if (update_agent->state == FWU_STATE_TRIAL) {
+ const struct image_info *image_info =
+ fw_directory_find_image_info(&update_agent->fw_directory, image_type_uuid);
+
+ if (image_info) {
+ if (fw_store_notify_accepted(update_agent->fw_store, image_info)) {
+ /* From the fw_store perspective, the update has
+ * been fully accepted.
+ */
+ status = fw_store_commit_to_update(update_agent->fw_store);
+ update_agent->state = FWU_STATE_REGULAR;
+
+ } else
+ /* Still more images to accept */
+ status = FWU_STATUS_SUCCESS;
+ } else
+ /* Unrecognised image uuid */
+ status = FWU_STATUS_UNKNOWN;
+ }
+
+ return status;
+}
+
+int update_agent_select_previous(struct update_agent *update_agent)
+{
+ int status = FWU_STATUS_DENIED;
+
+ if ((update_agent->state == FWU_STATE_TRIAL) ||
+ (update_agent->state == FWU_STATE_TRIAL_PENDING)) {
+ status = fw_store_revert_to_previous(update_agent->fw_store);
+ update_agent->state = FWU_STATE_REGULAR;
+ }
+
+ return status;
+}
+
+int update_agent_open(struct update_agent *update_agent, const struct uuid_octets *uuid,
+ uint32_t *handle)
+{
+ int status;
+
+ /* Pass UUID along a chain-of-responsibility until it's handled */
+ if (!open_image_directory(update_agent, uuid, handle, &status) &&
+ !open_fw_store_object(update_agent, uuid, handle, &status) &&
+ !open_fw_image(update_agent, uuid, handle, &status)) {
+ /* UUID not recognised */
+ status = FWU_STATUS_UNKNOWN;
+ }
+
+ return status;
+}
+
+int update_agent_commit(struct update_agent *update_agent, uint32_t handle, bool accepted)
+{
+ return stream_manager_close(&update_agent->stream_manager, handle, accepted);
+}
+
+int update_agent_write_stream(struct update_agent *update_agent, uint32_t handle,
+ const uint8_t *data, size_t data_len)
+{
+ return stream_manager_write(&update_agent->stream_manager, handle, data, data_len);
+}
+
+int update_agent_read_stream(struct update_agent *update_agent, uint32_t handle, uint8_t *buf,
+ size_t buf_size, size_t *read_len, size_t *total_len)
+{
+ return stream_manager_read(&update_agent->stream_manager, handle, buf, buf_size, read_len,
+ total_len);
+}
+
+static bool open_image_directory(struct update_agent *update_agent, const struct uuid_octets *uuid,
+ uint32_t *handle, int *status)
+{
+ struct uuid_octets target_uuid;
+
+ uuid_guid_octets_from_canonical(&target_uuid, FWU_DIRECTORY_CANONICAL_UUID);
+
+ if (uuid_is_equal(uuid->octets, target_uuid.octets)) {
+ /* Serialize a fresh view of the image directory */
+ size_t serialized_len = 0;
+
+ *status = img_dir_serializer_serialize(&update_agent->fw_directory,
+ update_agent->fw_store,
+ update_agent->image_dir_buf,
+ update_agent->image_dir_buf_size,
+ &serialized_len);
+
+ if (*status == FWU_STATUS_SUCCESS) {
+ *status = stream_manager_open_buffer_stream(&update_agent->stream_manager,
+ update_agent->image_dir_buf,
+ serialized_len, handle);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool open_fw_store_object(struct update_agent *update_agent, const struct uuid_octets *uuid,
+ uint32_t *handle, int *status)
+{
+ const uint8_t *exported_data;
+ size_t exported_data_len;
+
+ if (fw_store_export(update_agent->fw_store, uuid, &exported_data, &exported_data_len,
+ status)) {
+ if (*status == FWU_STATUS_SUCCESS) {
+ *status = stream_manager_open_buffer_stream(&update_agent->stream_manager,
+ exported_data,
+ exported_data_len, handle);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool open_fw_image(struct update_agent *update_agent, const struct uuid_octets *uuid,
+ uint32_t *handle, int *status)
+{
+ const struct image_info *image_info =
+ fw_directory_find_image_info(&update_agent->fw_directory, uuid);
+
+ if (image_info) {
+ if (update_agent->state == FWU_STATE_STAGING) {
+ struct installer *installer;
+
+ *status = fw_store_select_installer(update_agent->fw_store, image_info,
+ &installer);
+
+ if (*status == FWU_STATUS_SUCCESS) {
+ *status = stream_manager_open_install_stream(
+ &update_agent->stream_manager, update_agent->fw_store,
+ installer, image_info, handle);
+ }
+ } else {
+ /* Attempting to open a fw image when not staging */
+ *status = FWU_STATUS_DENIED;
+ }
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/components/service/fwu/agent/update_agent.h b/components/service/fwu/agent/update_agent.h
new file mode 100644
index 000000000..ea214ee00
--- /dev/null
+++ b/components/service/fwu/agent/update_agent.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FW_UPDATE_AGENT_H
+#define FW_UPDATE_AGENT_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "common/uuid/uuid.h"
+#include "fw_directory.h"
+#include "service/fwu/inspector/fw_inspector.h"
+#include "stream_manager.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct fw_store;
+
+/**
+ * \brief Update process states
+ *
+ * The update_agent is responsible for ensuring that only a valid update flow
+ * is followed by a client. To enforce the flow, public operations can only be
+ * used in a valid state that reflects the FWU-A behavioral model.
+ */
+enum fwu_state {
+ FWU_STATE_DEINITIALZED,
+ FWU_STATE_INITIALIZING,
+ FWU_STATE_REGULAR,
+ FWU_STATE_STAGING,
+ FWU_STATE_TRIAL_PENDING,
+ FWU_STATE_TRIAL
+};
+
+/**
+ * \brief update_agent structure definition
+ *
+ * An update_agent instance is responsible for coordinating firmware updates applied
+ * to a fw_store. An update_agent performs a security role by enforcing that a
+ * valid flow is performed to update the fw store.
+ */
+struct update_agent {
+ enum fwu_state state;
+ fw_inspector_inspect fw_inspect_method;
+ struct fw_store *fw_store;
+ struct fw_directory fw_directory;
+ struct stream_manager stream_manager;
+ uint8_t *image_dir_buf;
+ size_t image_dir_buf_size;
+};
+
+/**
+ * \brief Initialise the update_agent
+ *
+ * \param[in] update_agent The subject update_agent
+ * \param[in] boot_index The boot_index used by the bootloader
+ * \param[in] fw_inspect_method fw_inspector inspect method
+ * \param[in] fw_store The fw_store to manage
+ *
+ * \return Status (0 for success). Uses fwu protocol status codes.
+ */
+int update_agent_init(struct update_agent *update_agent, unsigned int boot_index,
+ fw_inspector_inspect fw_inspect_method, struct fw_store *fw_store);
+
+/**
+ * \brief De-initialise the update_agent
+ *
+ * \param[in] update_agent The subject update_agent
+ */
+void update_agent_deinit(struct update_agent *update_agent);
+
+/**
+ * \brief Begin staging
+ *
+ * \param[in] update_agent The subject update_agent
+ *
+ * \return 0 on successfully transitioning to the STAGING state
+ */
+int update_agent_begin_staging(struct update_agent *update_agent);
+
+/**
+ * \brief End staging
+ *
+ * \param[in] update_agent The subject update_agent
+ *
+ * \return 0 on successfully transitioning to the TRIAL state
+ */
+int update_agent_end_staging(struct update_agent *update_agent);
+
+/**
+ * \brief Cancel staging
+ *
+ * \param[in] update_agent The subject update_agent
+ *
+ * \return 0 on successfully transitioning to the REGULAR state
+ */
+int update_agent_cancel_staging(struct update_agent *update_agent);
+
+/**
+ * \brief Accept an updated image
+ *
+ * \param[in] update_agent The subject update_agent
+ * \param[in] image_type_uuid Identifies the image to accept
+ *
+ * \return Status (0 on success)
+ */
+int update_agent_accept(struct update_agent *update_agent,
+ const struct uuid_octets *image_type_uuid);
+
+/**
+ * \brief Select previous version
+ *
+ * Revert to a previous good version (if possible).
+ *
+ * \param[in] update_agent The subject update_agent
+ *
+ * \return Status (0 on success)
+ */
+int update_agent_select_previous(struct update_agent *update_agent);
+
+/**
+ * \brief Open a stream for accessing an fwu stream
+ *
+ * Used for reading or writing data for accessing images or other fwu
+ * related objects.
+ *
+ * \param[in] update_agent The subject update_agent
+ * \param[in] uuid Identifies the object to access
+ * \param[out] handle For subsequent read/write operations
+ *
+ * \return Status (0 on success)
+ */
+int update_agent_open(struct update_agent *update_agent, const struct uuid_octets *uuid,
+ uint32_t *handle);
+
+/**
+ * \brief Close a stream and commit any writes to the stream
+ *
+ * \param[in] update_agent The subject update_agent
+ * \param[in] handle The handle returned by open
+ * \param[in] accepted Initial accepted state of an image
+ *
+ * \return Status (0 on success)
+ */
+int update_agent_commit(struct update_agent *update_agent, uint32_t handle, bool accepted);
+
+/**
+ * \brief Write to a previously opened stream
+ *
+ * \param[in] update_agent The subject update_agent
+ * \param[in] handle The handle returned by open
+ * \param[in] data Pointer to data
+ * \param[in] data_len The data length
+ *
+ * \return Status (0 on success)
+ */
+int update_agent_write_stream(struct update_agent *update_agent, uint32_t handle,
+ const uint8_t *data, size_t data_len);
+
+/**
+ * \brief Read from a previously opened stream
+ *
+ * \param[in] update_agent The subject update_agent
+ * \param[in] handle The handle returned by open
+ * \param[in] buf Pointer to buffer to copy to
+ * \param[in] buf_size The size of the buffer
+ * \param[out] read_len The length of data read
+ * \param[out] total_len The total length of the object to read
+ *
+ * \return Status (0 on success)
+ */
+int update_agent_read_stream(struct update_agent *update_agent, uint32_t handle, uint8_t *buf,
+ size_t buf_size, size_t *read_len, size_t *total_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FW_UPDATE_AGENT_H */
diff --git a/components/service/fwu/config/component.cmake b/components/service/fwu/config/component.cmake
new file mode 100644
index 000000000..c653a416c
--- /dev/null
+++ b/components/service/fwu/config/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_configure.c"
+ )
diff --git a/components/service/fwu/config/fwu_configure.c b/components/service/fwu/config/fwu_configure.c
new file mode 100644
index 000000000..998673fc3
--- /dev/null
+++ b/components/service/fwu/config/fwu_configure.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "fwu_configure.h"
+
+#include <service/fwu/config/gpt/gpt_fwu_configure.h>
+
+#include "media/volume/factory/volume_factory.h"
+#include "media/volume/index/volume_index.h"
+#include "service/fwu/installer/factory/installer_factory.h"
+#include "service/fwu/installer/installer_index.h"
+
+int fwu_configure(const struct uuid_octets *device_uuids, size_t num_device_uuids)
+{
+ unsigned int location_id = 0;
+
+ volume_index_init();
+ installer_index_init();
+
+ for (size_t i = 0; i < num_device_uuids; i++) {
+ unsigned int new_location_count = 0;
+
+ int status = gpt_fwu_configure(&device_uuids[i], location_id, &new_location_count);
+
+ if (status)
+ return status;
+
+ location_id += new_location_count;
+ }
+
+ return 0;
+}
+
+void fwu_deconfigure(void)
+{
+ unsigned int index = 0;
+
+ /* Destroy installers */
+ while (1) {
+ struct installer *installer = installer_index_get(index);
+
+ if (installer)
+ installer_factory_destroy_installer(installer);
+ else
+ break;
+
+ ++index;
+ }
+
+ /* Destroy volumes */
+ index = 0;
+
+ while (1) {
+ struct volume *volume = volume_index_get(index);
+
+ if (volume)
+ volume_factory_destroy_volume(volume);
+ else
+ break;
+
+ ++index;
+ }
+
+ installer_index_clear();
+ volume_index_clear();
+}
diff --git a/components/service/fwu/config/fwu_configure.h b/components/service/fwu/config/fwu_configure.h
new file mode 100644
index 000000000..7137c015c
--- /dev/null
+++ b/components/service/fwu/config/fwu_configure.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FWU_CONFIGURE_H
+#define FWU_CONFIGURE_H
+
+#include "common/uuid/uuid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Configure installers and volumes for FWU
+ *
+ * Creates an FWU configuration consisting of a set of installers and volumes
+ * that provide the capabilities needed to update images residing on the set
+ * of storage devices identified by the input set of device UUIDs. Created
+ * installers are added to the singleton installer_index and created volumes
+ * are added to the volume_index. Related installers and volumes are grouped
+ * by assigning location IDs.
+ *
+ * \param[in] device_uuids Array of device UUIDs
+ * \param[in] num_device_uuids Number of UUIDs in the array
+ *
+ * \return Configuration status (0 for success)
+ */
+int fwu_configure(const struct uuid_octets *device_uuids, size_t num_device_uuids);
+
+/**
+ * \brief De-configure the FWU configuration
+ *
+ * Deregisters and destroys all installers and volumes.
+ */
+void fwu_deconfigure(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FWU_CONFIGURE_H */
diff --git a/components/service/fwu/config/gpt/component.cmake b/components/service/fwu/config/gpt/component.cmake
new file mode 100644
index 000000000..4950aa23a
--- /dev/null
+++ b/components/service/fwu/config/gpt/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/gpt_fwu_configure.c"
+ )
diff --git a/components/service/fwu/config/gpt/gpt_fwu_configure.c b/components/service/fwu/config/gpt/gpt_fwu_configure.c
new file mode 100644
index 000000000..e5cfed3d0
--- /dev/null
+++ b/components/service/fwu/config/gpt/gpt_fwu_configure.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "gpt_fwu_configure.h"
+
+#include <errno.h>
+#include <stdint.h>
+
+#include "media/disk/gpt_iterator/gpt_iterator.h"
+#include "media/disk/guid.h"
+#include "media/volume/factory/volume_factory.h"
+#include "media/volume/index/volume_index.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+#include "service/fwu/installer/factory/installer_factory.h"
+#include "service/fwu/installer/installer.h"
+#include "service/fwu/installer/installer_index.h"
+#include "trace.h"
+
+static struct installer *
+create_and_register_installers(const struct uuid_octets *partition_type_uuid,
+ unsigned int location_id);
+
+static int create_and_register_metadata_volume(const struct uuid_octets *device_uuid,
+ gpt_entry_t *entry, unsigned int *metadata_count);
+
+int gpt_fwu_configure(const struct uuid_octets *device_uuid, unsigned int initial_location_id,
+ unsigned int *location_count)
+{
+ struct uuid_octets gpt_guid;
+ unsigned int next_location_id = initial_location_id;
+ unsigned int metadata_partition_count = 0;
+
+ *location_count = 0;
+
+ uuid_guid_octets_from_canonical(&gpt_guid, DISK_GUID_UNIQUE_PARTITION_DISK_HEADER);
+ struct volume *gpt_volume = volume_factory_create_volume(&gpt_guid, device_uuid);
+
+ if (!gpt_volume) {
+ /* The case where there is no GPT volume is not necessarily an error.
+ * It could just mean that an alternative configuration method is required
+ * for this storage device.
+ */
+ IMSG("No disk header volume");
+ return 0;
+ }
+
+ /* Attempt to initialise a gpt_iterator. This requires a well-formed GPT to
+ * be present. Again, if there's not one, this is shouldn't be treated as
+ * an error as an alternative configuration method may be used,
+ */
+ struct gpt_iterator gpt_iter;
+ int status = gpt_iterator_init(&gpt_iter, gpt_volume);
+
+ if (status) {
+ IMSG("No GPT found");
+ status = 0;
+ goto abnormal_exit;
+ }
+
+ /* Iterate over partition table and extend configuration for updatable partitions */
+ gpt_iterator_first(&gpt_iter);
+
+ while (!gpt_iterator_is_done(&gpt_iter)) {
+ gpt_entry_t entry;
+
+ status = gpt_iterator_current(&gpt_iter, &entry);
+
+ if (status) {
+ EMSG("Failed to read GPT entry: %d", status);
+ goto abnormal_exit;
+ }
+
+ const struct uuid_octets *partition_type_guid =
+ (const struct uuid_octets *)&entry.type_uuid;
+
+ /* Skip unused entry */
+ if (uuid_is_nil(partition_type_guid->octets)) {
+ gpt_iterator_next(&gpt_iter);
+ continue;
+ }
+
+ /* Determine if any installers are available to handle some form of
+ * image installation for the location reflected by the partition type
+ * GUID. If a partition of the same type has already been encountered
+ * and the installation is supported, there will already be one or more
+ * registered installers.
+ */
+ struct installer *installer =
+ installer_index_find_by_location_uuid(partition_type_guid);
+
+ if (!installer) {
+ /* No installer for the partition type has yet been registered. This
+ * is either because this is the first partition of this type to be
+ * encountered or because the partition is not updatable. Find out by
+ * attempting to construct one or more installers.
+ */
+ installer = create_and_register_installers(partition_type_guid,
+ next_location_id);
+
+ if (installer)
+ ++next_location_id;
+ }
+
+ if (installer) {
+ /* This configurator relies on the partition name to identify the bank
+ * index that the partition corresponds to. This convention also needs
+ * to be used by the bootloader to ensure that there is a consistent
+ * view of bank index. The name should include the bank index as the
+ * first character e.g. 0:AP-FW.
+ */
+ unsigned int bank_index;
+
+ if (entry.name[0] == '0')
+ bank_index = 0;
+ else if (entry.name[0] == '1')
+ bank_index = 1;
+ else {
+ EMSG("Invalid bank index in partition name");
+ goto abnormal_exit;
+ }
+
+ /* This partition is updatable so construct and register a volume
+ * to provide access to storage.
+ */
+ struct volume *volume = volume_factory_create_volume(
+ (const struct uuid_octets *)&entry.unique_uuid, device_uuid);
+
+ if (!volume) {
+ EMSG("Failed to create volume");
+ goto abnormal_exit;
+ }
+
+ status = volume_index_add(banked_volume_id(installer->location_id,
+ banked_usage_id(bank_index)),
+ volume);
+
+ if (status) {
+ volume_factory_destroy_volume(volume);
+ EMSG("Failed to register volume");
+ goto abnormal_exit;
+ }
+
+ } else {
+ /* Not an updatable partition but it might be for FWU metadata */
+ status = create_and_register_metadata_volume(device_uuid, &entry,
+ &metadata_partition_count);
+
+ if (status) {
+ EMSG("Failed to create metadata volume");
+ goto abnormal_exit;
+ }
+ }
+
+ gpt_iterator_next(&gpt_iter);
+ }
+
+abnormal_exit:
+ gpt_iterator_deinit(&gpt_iter);
+ volume_factory_destroy_volume(gpt_volume);
+
+ /* Count of the number of new locations added */
+ *location_count = next_location_id - initial_location_id;
+
+ return status;
+}
+
+static struct installer *
+create_and_register_installers(const struct uuid_octets *partition_type_uuid,
+ unsigned int location_id)
+{
+ /* Attempt to create a complete set of installers for updating images
+ * contained within a partition of the specified type. The installer_factory
+ * holds the policy over which partitions are updatable and with what type
+ * of installer. If at least one installer ends up being constructed,
+ * a pointer to any of the constructed installers is returned.
+ */
+ struct installer *last_constructed = NULL;
+ struct installer *installer = NULL;
+
+ installer = installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME, location_id,
+ partition_type_uuid);
+
+ if (installer) {
+ installer_index_register(installer);
+ last_constructed = installer;
+ }
+
+ installer = installer_factory_create_installer(INSTALL_TYPE_SUB_VOLUME, location_id,
+ partition_type_uuid);
+
+ if (installer) {
+ installer_index_register(installer);
+ last_constructed = installer;
+ }
+
+ installer = installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME_COPY, location_id,
+ partition_type_uuid);
+
+ if (installer) {
+ installer_index_register(installer);
+ last_constructed = installer;
+ }
+
+ return last_constructed;
+}
+
+static int create_and_register_metadata_volume(const struct uuid_octets *device_uuid,
+ gpt_entry_t *entry, unsigned int *metadata_count)
+{
+ struct uuid_octets guid;
+
+ uuid_guid_octets_from_canonical(&guid, DISK_GUID_PARTITION_TYPE_FWU_METADATA);
+
+ if (!uuid_is_equal(guid.octets, (const uint8_t *)&entry->type_uuid))
+ return 0;
+
+ uint32_t volume_id;
+
+ if (*metadata_count == 0)
+ volume_id = BANKED_VOLUME_ID_PRIMARY_METADATA;
+ else if (*metadata_count == 1)
+ volume_id = BANKED_VOLUME_ID_BACKUP_METADATA;
+ else
+ /* Ignore any additional metadata partitions */
+ return 0;
+
+ struct volume *volume = volume_factory_create_volume(
+ (const struct uuid_octets *)&entry->unique_uuid, device_uuid);
+
+ if (!volume)
+ return -EIO;
+
+ if (volume_index_add(volume_id, volume)) {
+ volume_factory_destroy_volume(volume);
+ return -EIO;
+ }
+
+ *metadata_count += 1;
+
+ return 0;
+} \ No newline at end of file
diff --git a/components/service/fwu/config/gpt/gpt_fwu_configure.h b/components/service/fwu/config/gpt/gpt_fwu_configure.h
new file mode 100644
index 000000000..d6856da1b
--- /dev/null
+++ b/components/service/fwu/config/gpt/gpt_fwu_configure.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef GPT_FWU_CONFIGURE_H
+#define GPT_FWU_CONFIGURE_H
+
+#include "common/uuid/uuid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief GPT based FWU configure method
+ *
+ * An FWU configuration comprises a set of installers and volume objects that
+ * enables all updatable firmware images to be updated by the update agent. This
+ * configure method uses partition information contained within a UEFI formatted
+ * storage device to extend the FWU configuration to cover all updatable partitions
+ * on the device. The configurator iterates over the GPT and progressively adds
+ * the necessary installers and volumes to the configuration. To allow for multiple
+ * configuration steps (e.g. for multiple devices), the initial location ID is
+ * passed as a parameter and a count of the number of locations added is returned.
+ *
+ * \param[in] device_uuid Identifies the target device
+ * \param[in] initial_location_id Initial location ID
+ * \param[out] location_count The number of locations added
+ *
+ * \return Status code (0 for success)
+ */
+int gpt_fwu_configure(const struct uuid_octets *device_uuid, unsigned int initial_location_id,
+ unsigned int *location_count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GPT_FWU_CONFIGURE_H */
diff --git a/components/service/fwu/fw_store/banked/bank_scheme.h b/components/service/fwu/fw_store/banked/bank_scheme.h
new file mode 100644
index 000000000..5696f3913
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/bank_scheme.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BANKED_FW_STORE_BANK_SCHEME_H
+#define BANKED_FW_STORE_BANK_SCHEME_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Definitions for an A/B banked scheme.
+ */
+#define BANK_SCHEME_NUM_BANKS (2)
+
+/**
+ * \brief Returns the index of the next bank to use
+ *
+ * Given a bank index, returns the index of the next bank to use.
+ *
+ * \param[in] bank_index
+ *
+ * \return Index of next bank to use
+ */
+static inline uint32_t bank_scheme_next_index(uint32_t bank_index)
+{
+ return (bank_index == 0) ? 1 : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BANKED_FW_STORE_BANK_SCHEME_H */
diff --git a/components/service/fwu/fw_store/banked/bank_tracker.c b/components/service/fwu/fw_store/banked/bank_tracker.c
new file mode 100644
index 000000000..5f80d0152
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/bank_tracker.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "bank_tracker.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+void bank_tracker_init(struct bank_tracker *subject)
+{
+ memset(subject, 0, sizeof(struct bank_tracker));
+}
+
+void bank_tracker_deinit(struct bank_tracker *subject)
+{
+ (void)subject;
+}
+
+void bank_tracker_accept(struct bank_tracker *subject, unsigned int bank_index,
+ unsigned int image_index)
+{
+ assert(bank_index < BANK_SCHEME_NUM_BANKS);
+ assert(image_index < FWU_MAX_FW_DIRECTORY_ENTRIES);
+
+ subject->bank_state[bank_index].is_accepted[image_index] = true;
+}
+
+void bank_tracker_copy_accept(struct bank_tracker *subject, unsigned int from_bank_index,
+ unsigned int to_bank_index, unsigned int image_index)
+{
+ assert(from_bank_index < BANK_SCHEME_NUM_BANKS);
+ assert(to_bank_index < BANK_SCHEME_NUM_BANKS);
+ assert(image_index < FWU_MAX_FW_DIRECTORY_ENTRIES);
+
+ subject->bank_state[to_bank_index].is_accepted[image_index] =
+ subject->bank_state[from_bank_index].is_accepted[image_index];
+}
+
+void bank_tracker_set_no_content(struct bank_tracker *subject, unsigned int bank_index)
+{
+ assert(bank_index < BANK_SCHEME_NUM_BANKS);
+
+ subject->bank_state[bank_index].is_content = false;
+
+ for (unsigned int i = 0; i < FWU_MAX_FW_DIRECTORY_ENTRIES; i++)
+ subject->bank_state[bank_index].is_accepted[i] = false;
+}
+
+void bank_tracker_set_holds_content(struct bank_tracker *subject, unsigned int bank_index)
+{
+ assert(bank_index < BANK_SCHEME_NUM_BANKS);
+
+ subject->bank_state[bank_index].is_content = true;
+}
+
+void bank_tracker_set_holds_accepted_content(struct bank_tracker *subject, unsigned int bank_index)
+{
+ assert(bank_index < BANK_SCHEME_NUM_BANKS);
+
+ subject->bank_state[bank_index].is_content = true;
+
+ for (unsigned int i = 0; i < FWU_MAX_FW_DIRECTORY_ENTRIES; i++)
+ subject->bank_state[bank_index].is_accepted[i] = true;
+}
+
+bool bank_tracker_is_content(const struct bank_tracker *subject, unsigned int bank_index)
+{
+ assert(bank_index < BANK_SCHEME_NUM_BANKS);
+
+ return subject->bank_state[bank_index].is_content;
+}
+
+bool bank_tracker_is_accepted(const struct bank_tracker *subject, unsigned int bank_index,
+ unsigned int image_index)
+{
+ assert(bank_index < BANK_SCHEME_NUM_BANKS);
+ assert(image_index < FWU_MAX_FW_DIRECTORY_ENTRIES);
+
+ return subject->bank_state[bank_index].is_accepted[image_index];
+}
+
+bool bank_tracker_is_all_accepted(const struct bank_tracker *subject, unsigned int bank_index,
+ unsigned int num_images)
+{
+ assert(bank_index < BANK_SCHEME_NUM_BANKS);
+ assert(num_images <= FWU_MAX_FW_DIRECTORY_ENTRIES);
+
+ for (unsigned int image_index = 0; image_index < num_images; image_index++) {
+ if (!subject->bank_state[bank_index].is_accepted[image_index])
+ return false;
+ }
+
+ return true;
+}
diff --git a/components/service/fwu/fw_store/banked/bank_tracker.h b/components/service/fwu/fw_store/banked/bank_tracker.h
new file mode 100644
index 000000000..b2f9b46ec
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/bank_tracker.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BANK_TRACKER_H
+#define BANK_TRACKER_H
+
+#include <stdbool.h>
+
+#include "bank_scheme.h"
+#include "service/fwu/agent/fw_directory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief bank_tracker structure definition
+ *
+ * Tracks the state of fw_store banks.
+ */
+struct bank_tracker {
+ struct {
+ /* True if bank holds content */
+ bool is_content;
+
+ /* Image accepted state for images contained in the bank */
+ bool is_accepted[FWU_MAX_FW_DIRECTORY_ENTRIES];
+
+ } bank_state[BANK_SCHEME_NUM_BANKS];
+};
+
+/**
+ * \brief Initialize the bank_tracker
+ *
+ * \param[in] subject This instance
+ */
+void bank_tracker_init(struct bank_tracker *subject);
+
+/**
+ * \brief De-initialize the bank_tracker
+ *
+ * \param[in] subject This instance
+ */
+void bank_tracker_deinit(struct bank_tracker *subject);
+
+/**
+ * \brief Mark image as accepted
+ *
+ * \param[in] subject This instance
+ * \param[in] bank_index The firmware bank
+ * \param[in] image_index The image index (from fw_directory)
+ */
+void bank_tracker_accept(struct bank_tracker *subject, unsigned int bank_index,
+ unsigned int image_index);
+
+/**
+ * \brief Copy image accept state
+ *
+ * \param[in] subject This instance
+ * \param[in] from_bank_index Copy accepted state from bank index
+ * \param[in] to_bank_index Copy accepted state to bank index
+ * \param[in] image_index The image index (from fw_directory)
+ */
+void bank_tracker_copy_accept(struct bank_tracker *subject, unsigned int from_bank_index,
+ unsigned int to_bank_index, unsigned int image_index);
+
+/**
+ * \brief Sets bank as holding no content
+ *
+ * \param[in] subject This instance
+ * \param[in] bank_index The firmware bank
+ */
+void bank_tracker_set_no_content(struct bank_tracker *subject, unsigned int bank_index);
+
+/**
+ * \brief Set bank as holding content
+ *
+ * \param[in] subject This instance
+ * \param[in] bank_index The firmware bank
+ */
+void bank_tracker_set_holds_content(struct bank_tracker *subject, unsigned int bank_index);
+
+/**
+ * \brief Set bank as holding fully accepted content
+ *
+ * \param[in] subject This instance
+ * \param[in] bank_index The firmware bank
+ */
+void bank_tracker_set_holds_accepted_content(struct bank_tracker *subject, unsigned int bank_index);
+
+/**
+ * \brief Check if bank holds contents
+ *
+ * \param[in] subject This instance
+ * \param[in] bank_index The firmware bank
+ *
+ * \return True if bank holds content
+ */
+bool bank_tracker_is_content(const struct bank_tracker *subject, unsigned int bank_index);
+
+/**
+ * \brief Check if image is accepted
+ *
+ * \param[in] subject This instance
+ * \param[in] bank_index The firmware bank
+ * \param[in] image_index The image index
+ *
+ * \return True if an image has been accepted
+ */
+bool bank_tracker_is_accepted(const struct bank_tracker *subject, unsigned int bank_index,
+ unsigned int image_index);
+
+/**
+ * \brief Check if all images are accepted
+ *
+ * \param[in] subject This instance
+ * \param[in] bank_index The firmware bank
+ * \param[in] num_images Number of images to consider
+ *
+ * \return True if all images have been accepted
+ */
+bool bank_tracker_is_all_accepted(const struct bank_tracker *subject, unsigned int bank_index,
+ unsigned int num_images);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BANK_TRACKER_H */
diff --git a/components/service/fwu/fw_store/banked/banked_fw_store.c b/components/service/fwu/fw_store/banked/banked_fw_store.c
new file mode 100644
index 000000000..b987b486b
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/banked_fw_store.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "banked_fw_store.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "bank_scheme.h"
+#include "common/uuid/uuid.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/installer/installer.h"
+#include "service/fwu/installer/installer_index.h"
+#include "volume_id.h"
+
+static int activate_installer(struct fw_store *fw_store, struct installer *installer,
+ uint32_t location_id)
+{
+ int status = FWU_STATUS_UNKNOWN;
+
+ /* An image has been presented that requires a new installer to
+ * be activated. This involves associating the installer with
+ * the correct storage volumes that reflect the current bank
+ * state. Active installers are held in a linked list during
+ * the installation phase of an update transaction.
+ */
+ unsigned int update_volume_id =
+ banked_volume_id(location_id, banked_usage_id(fw_store->update_index));
+
+ unsigned int current_volume_id =
+ banked_volume_id(location_id, banked_usage_id(fw_store->boot_index));
+
+ status = installer_begin(installer, current_volume_id, update_volume_id);
+
+ if (status == FWU_STATUS_SUCCESS) {
+ /* Add to list of active installers */
+ installer->next = fw_store->active_installers;
+ fw_store->active_installers = installer;
+ }
+
+ return status;
+}
+
+static void copy_accepted_state_for_location(struct fw_store *fw_store, uint32_t location_id)
+{
+ size_t index = 0;
+
+ while (1) {
+ const struct image_info *image_info =
+ fw_directory_get_image_info(fw_store->fw_directory, index);
+
+ if (image_info) {
+ if (image_info->location_id == location_id)
+ bank_tracker_copy_accept(&fw_store->bank_tracker,
+ fw_store->boot_index,
+ fw_store->update_index,
+ image_info->image_index);
+ } else
+ break;
+
+ ++index;
+ }
+}
+
+static int install_unchanged_images(struct fw_store *fw_store)
+{
+ int status = FWU_STATUS_SUCCESS;
+ size_t num_locations = 0;
+ const uint32_t *location_ids = installer_index_get_location_ids(&num_locations);
+
+ /* Iterate over each of the location_ids that require updating for a viable update.
+ * If there are locations without an active installer, attempt to copy from the
+ * currently active bank.
+ */
+ for (size_t i = 0; !status && i < num_locations; i++) {
+ bool is_installer_found = false;
+ uint32_t location_id = location_ids[i];
+ struct installer *installer = fw_store->active_installers;
+
+ while (installer) {
+ if ((installer->location_id == location_id) &&
+ !installer_status(installer)) {
+ /* There was an installer for this location and the installation
+ * went without errors.
+ */
+ is_installer_found = true;
+ break;
+ }
+
+ installer = installer->next;
+ }
+
+ if (!is_installer_found) {
+ /* There is no installer for the location so assume the active bank
+ * should be copied. This relies on the platform integrator providing
+ * a suitable installer to do the copying. It's a legitimate platform
+ * configuration to not provide one and only allow updates that consist
+ * of images for all locations.
+ */
+ struct installer *copy_installer =
+ installer_index_find(INSTALL_TYPE_WHOLE_VOLUME_COPY, location_id);
+
+ if (copy_installer) {
+ /* A copy installer doesn't accept any external data. Instead, it
+ * copies from the current volume to the update volume during the
+ * finalize operation.
+ */
+ unsigned int update_volume_id = banked_volume_id(
+ location_id, banked_usage_id(fw_store->update_index));
+
+ unsigned int current_volume_id = banked_volume_id(
+ location_id, banked_usage_id(fw_store->boot_index));
+
+ status = installer_begin(copy_installer, current_volume_id,
+ update_volume_id);
+
+ if (status == FWU_STATUS_SUCCESS) {
+ status = installer_finalize(copy_installer);
+
+ /* If a whole volume image was successfully copied from
+ * the currently active bank to the update bank, also copy the
+ * corresponding accepted state for all images associated with the
+ * location. This saves a client from having to re-accept images
+ * that have already been accepted during a previous update.
+ */
+ if (status == FWU_STATUS_SUCCESS)
+ copy_accepted_state_for_location(fw_store,
+ location_id);
+ }
+
+ } else {
+ /* Platform configuration doesn't include a suitable copy installer
+ * so treat this update attempt as not viable.
+ */
+ status = FWU_STATUS_NOT_AVAILABLE;
+ }
+ }
+ }
+
+ return status;
+}
+
+int banked_fw_store_init(struct fw_store *fw_store, const struct metadata_serializer *serializer)
+{
+ fw_store->fw_directory = NULL;
+ fw_store->active_installers = NULL;
+
+ fw_store->update_index = 0;
+ fw_store->boot_index = 0;
+
+ bank_tracker_init(&fw_store->bank_tracker);
+
+ return metadata_manager_init(&fw_store->metadata_manager, serializer);
+}
+
+void banked_fw_store_deinit(struct fw_store *fw_store)
+{
+ bank_tracker_deinit(&fw_store->bank_tracker);
+ metadata_manager_deinit(&fw_store->metadata_manager);
+}
+
+int fw_store_synchronize(struct fw_store *fw_store, struct fw_directory *fw_dir,
+ unsigned int boot_index)
+{
+ int status = FWU_STATUS_UNKNOWN;
+
+ /* Associate with the fw_directory */
+ fw_store->fw_directory = fw_dir;
+
+ /* Note the boot index decision made by the boot loader and choose an
+ * alternative index for a prospective update.
+ */
+ fw_store->boot_index = boot_index;
+ fw_store->update_index = bank_scheme_next_index(boot_index);
+
+ /* Start building a view of the boot_info that will be advertised by the fw_directory */
+ struct boot_info boot_info = { 0 };
+
+ boot_info.boot_index = boot_index;
+
+ /* Ensure that FWU metadata is in a good state. Corruption can occur
+ * due to power failures. The following steps will repair a corrupted
+ * metadata copy or generate fresh metadata if necessary.
+ */
+ status = metadata_manager_check_and_repair(&fw_store->metadata_manager, fw_dir);
+
+ if (status != FWU_STATUS_SUCCESS) {
+ /* No viable metadata exists so a fresh version needs to be created. We
+ * can only assume that the boot_index is good. Also assume that it is
+ * fully accepted as there is no knowledge that a rollback to a previous
+ * bank is possible.
+ */
+ boot_info.active_index = boot_index;
+ boot_info.previous_active_index = boot_index;
+
+ bank_tracker_set_holds_accepted_content(&fw_store->bank_tracker,
+ fw_store->boot_index);
+
+ status = metadata_manager_update(&fw_store->metadata_manager,
+ boot_info.active_index,
+ boot_info.previous_active_index, fw_dir,
+ &fw_store->bank_tracker);
+
+ } else {
+ /* Metadata was successfully loaded from storage so synchronize local
+ * state to the NV state reflected by the metadata.
+ */
+ status = metadata_manager_get_active_indices(&fw_store->metadata_manager,
+ &boot_info.active_index,
+ &boot_info.previous_active_index);
+
+ /* Synchronize image approval state with NV information contained in the metadata */
+ metadata_manager_preload_bank_tracker(&fw_store->metadata_manager,
+ &fw_store->bank_tracker);
+
+ /* Check for the case where the bootloader has not booted from the active bank.
+ * This will occur when boot loader conditions for a successful boot are not
+ * met and it was necessary to fallback to a previous bank. To prevent
+ * repeated failed boots, the metadata is updated in-line with the
+ * bootloader's decision.
+ */
+ if ((status == FWU_STATUS_SUCCESS) && (boot_index != boot_info.active_index)) {
+ boot_info.active_index = boot_index;
+ boot_info.previous_active_index = boot_index;
+
+ status = metadata_manager_update(&fw_store->metadata_manager,
+ boot_info.active_index,
+ boot_info.previous_active_index, fw_dir,
+ &fw_store->bank_tracker);
+ }
+ }
+
+ /* Synchronize the fw_directory's view of the boot info */
+ fw_directory_set_boot_info(fw_dir, &boot_info);
+
+ return status;
+}
+
+int fw_store_begin_install(struct fw_store *fw_store)
+{
+ assert(!fw_store->active_installers);
+
+ /* Begin the update transaction with the update bank marked as holding
+ * no content and all updatable images in the unaccepted state. Installed
+ * images may be committed as accepted after installation or accepted
+ * during the trial state.
+ */
+ bank_tracker_set_no_content(&fw_store->bank_tracker, fw_store->update_index);
+
+ /* Protect the update bank from use while the installation is in
+ * progress by setting the active and previous active indices to be equal.
+ * If a system restart occurs during installation, this prevents the
+ * possibility of the boot loader attempting to boot from a bank in a partially
+ * installed state.
+ */
+ int status = metadata_manager_update(&fw_store->metadata_manager, fw_store->boot_index,
+ fw_store->boot_index, fw_store->fw_directory,
+ &fw_store->bank_tracker);
+
+ return status;
+}
+
+void fw_store_cancel_install(struct fw_store *fw_store)
+{
+ /* Abort all active installers - each installer will do its best to
+ * clean-up to a state where a follow-in installation is possible.
+ */
+ while (fw_store->active_installers) {
+ struct installer *installer = fw_store->active_installers;
+
+ fw_store->active_installers = installer->next;
+
+ installer_abort(installer);
+ }
+}
+
+int fw_store_finalize_install(struct fw_store *fw_store)
+{
+ int status = FWU_STATUS_NOT_AVAILABLE;
+
+ /* Treat no active installers as an error. This would occur if no
+ * images where actually installed during the transaction.
+ */
+ bool is_error = !fw_store->active_installers;
+
+ /* If there are firmware locations that are unchanged after
+ * installation, it may be necessary to copy active images to
+ * the update bank to ensure that the update bank is fully
+ * populated. This will be needed if an incoming update package
+ * only contains images for some locations.
+ */
+ if (!is_error) {
+ status = install_unchanged_images(fw_store);
+ is_error = (status != FWU_STATUS_SUCCESS);
+ }
+
+ /* Finalize all active installers - each installer will perform any
+ * actions needed to make installed images ready for use. For example,
+ * for a component installer where only a subset of images were updated,
+ * the finalize step can be used to copy any images that weren't updated
+ * from the currently active storage volume.
+ */
+ while (fw_store->active_installers) {
+ struct installer *installer = fw_store->active_installers;
+
+ fw_store->active_installers = installer->next;
+
+ if (!is_error) {
+ status = installer_finalize(installer);
+ is_error = (status != FWU_STATUS_SUCCESS);
+
+ } else
+ installer_abort(installer);
+ }
+
+ if (is_error) {
+ return (status != FWU_STATUS_SUCCESS) ? status : FWU_STATUS_NOT_AVAILABLE;
+ }
+
+ /* All installers finalized successfully so mark update bank as holding
+ * content and signal to boot loader that the update is ready for a trial
+ * by promoting the update bank to being the active bank.
+ */
+ bank_tracker_set_holds_content(&fw_store->bank_tracker, fw_store->update_index);
+
+ status = metadata_manager_update(&fw_store->metadata_manager, fw_store->update_index,
+ fw_store->boot_index, fw_store->fw_directory,
+ &fw_store->bank_tracker);
+
+ return status;
+}
+
+int fw_store_select_installer(struct fw_store *fw_store, const struct image_info *image_info,
+ struct installer **installer)
+{
+ int status = FWU_STATUS_UNKNOWN;
+
+ *installer = NULL;
+
+ struct installer *selected_installer =
+ installer_index_find(image_info->install_type, image_info->location_id);
+
+ if (selected_installer) {
+ /* An installer is available to handle the incoming image. An installer
+ * will potentially handle multiple images as part of an update transaction.
+ * If this is the first, the installer needs to be activated.
+ */
+ if (installer_is_active(selected_installer) ||
+ (status = activate_installer(fw_store, selected_installer,
+ image_info->location_id),
+ status == FWU_STATUS_SUCCESS)) {
+ status = installer_open(selected_installer, image_info);
+
+ if (status == FWU_STATUS_SUCCESS)
+ *installer = selected_installer;
+ }
+ }
+
+ return status;
+}
+
+int fw_store_write_image(struct fw_store *fw_store, struct installer *installer,
+ const uint8_t *data, size_t data_len)
+{
+ if (!installer_is_active(installer))
+ /* Attempting to write to an inactive installer */
+ return FWU_STATUS_DENIED;
+
+ int status = installer_write(installer, data, data_len);
+
+ return status;
+}
+
+int fw_store_commit_image(struct fw_store *fw_store, struct installer *installer,
+ const struct image_info *image_info, bool accepted)
+{
+ if (!installer_is_active(installer))
+ /* Attempting to commit an inactive installer */
+ return FWU_STATUS_DENIED;
+
+ int status = installer_commit(installer);
+
+ if ((status == FWU_STATUS_SUCCESS) && accepted)
+ bank_tracker_accept(&fw_store->bank_tracker, fw_store->update_index,
+ image_info->image_index);
+
+ return status;
+}
+
+bool fw_store_notify_accepted(struct fw_store *fw_store, const struct image_info *image_info)
+{
+ unsigned int num_images = fw_directory_num_images(fw_store->fw_directory);
+
+ bank_tracker_accept(&fw_store->bank_tracker, fw_store->boot_index, image_info->image_index);
+
+ int status = metadata_manager_update(&fw_store->metadata_manager, fw_store->boot_index,
+ fw_store->update_index, fw_store->fw_directory,
+ &fw_store->bank_tracker);
+
+ return (status == FWU_STATUS_SUCCESS) &&
+ bank_tracker_is_all_accepted(&fw_store->bank_tracker, fw_store->boot_index,
+ num_images);
+}
+
+bool fw_store_is_accepted(const struct fw_store *fw_store, const struct image_info *image_info)
+{
+ return bank_tracker_is_accepted(&fw_store->bank_tracker, fw_store->boot_index,
+ image_info->image_index);
+}
+
+bool fw_store_is_trial(const struct fw_store *fw_store)
+{
+ const struct boot_info *boot_info = fw_directory_get_boot_info(fw_store->fw_directory);
+ unsigned int num_images = fw_directory_num_images(fw_store->fw_directory);
+
+ return (boot_info->boot_index == boot_info->active_index) &&
+ !bank_tracker_is_all_accepted(&fw_store->bank_tracker, fw_store->boot_index,
+ num_images);
+}
+
+int fw_store_commit_to_update(struct fw_store *fw_store)
+{
+ (void)fw_store;
+
+ /* Currently, the final commitment to an update is made by the boot loader
+ * when anti-rollback counters are advanced after a reboot. For deployments
+ * where anti-rollback counters are managed by the update agent, the necessary
+ * management logic should be add here.
+ */
+ return FWU_STATUS_SUCCESS;
+}
+
+int fw_store_revert_to_previous(struct fw_store *fw_store)
+{
+ uint32_t active_index;
+ uint32_t previous_active_index;
+
+ int status = metadata_manager_get_active_indices(&fw_store->metadata_manager, &active_index,
+ &previous_active_index);
+
+ if (status)
+ return status;
+
+ if (active_index == fw_store->boot_index) {
+ /* Update has been activated via a reboot */
+ active_index = previous_active_index;
+ previous_active_index = fw_store->boot_index;
+ fw_store->update_index = bank_scheme_next_index(active_index);
+
+ } else {
+ /* Update has not yet been activated */
+ previous_active_index = active_index;
+ active_index = fw_store->boot_index;
+ fw_store->update_index = bank_scheme_next_index(active_index);
+ }
+
+ /* Ensure all images for the new active bank are marked as accepted */
+ bank_tracker_set_holds_accepted_content(&fw_store->bank_tracker, active_index);
+
+ /* Update the FWU metadata to the pre-update state */
+ status = metadata_manager_update(&fw_store->metadata_manager, active_index,
+ previous_active_index, fw_store->fw_directory,
+ &fw_store->bank_tracker);
+
+ return status;
+}
+
+bool fw_store_export(struct fw_store *fw_store, const struct uuid_octets *uuid,
+ const uint8_t **data, size_t *data_len, int *status)
+{
+ struct uuid_octets target_uuid;
+
+ /* Check for request to export the FWU metadata */
+ uuid_guid_octets_from_canonical(&target_uuid, FWU_METADATA_CANONICAL_UUID);
+
+ if (uuid_is_equal(uuid->octets, target_uuid.octets)) {
+ bool is_dirty;
+
+ *status = metadata_manager_fetch(&fw_store->metadata_manager, data, data_len,
+ &is_dirty);
+
+ /* is_dirty value is not yet returned when exporting the FWU Metadata but this
+ * may be added to allow for deployments where metadata is written by the client
+ * to allow unnecessary writes to be avoided.
+ */
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/components/service/fwu/fw_store/banked/banked_fw_store.h b/components/service/fwu/fw_store/banked/banked_fw_store.h
new file mode 100644
index 000000000..5e35e7718
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/banked_fw_store.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BANKED_FW_STORE_H
+#define BANKED_FW_STORE_H
+
+#include <stdint.h>
+
+#include "bank_tracker.h"
+#include "metadata_manager.h"
+#include "service/fwu/fw_store/fw_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct installer;
+struct metadata_serializer;
+
+/**
+ * \brief Banked fw_store structure definition
+ *
+ * A banked fw_store manages updates to an A/B banked firmware store. The
+ * implementation realizes the common fw_store interface. The banked fw_store
+ * can handle both Nwd and Swd image installation.
+ */
+struct fw_store {
+ const struct fw_directory *fw_directory;
+ struct installer *active_installers;
+ struct metadata_manager metadata_manager;
+ struct bank_tracker bank_tracker;
+ uint32_t update_index;
+ uint32_t boot_index;
+};
+
+/**
+ * \brief Initialize a banked fw_store
+ *
+ * Initializes a banked fw_store that manages updates according to the Arm
+ * FWU-A specification. The provided metadata_serializer should have been
+ * selected for compatibility with the bootloader.
+ *
+ * \param[in] fw_store The subject fw_store
+ * \param[in] serializer The metadata_serializer to use
+ *
+ * \return FWU status code
+ */
+int banked_fw_store_init(struct fw_store *fw_store, const struct metadata_serializer *serializer);
+
+/**
+ * \brief De-initialize a banked_fw_store
+ *
+ * \param[in] fw_store The subject fw_store
+ */
+void banked_fw_store_deinit(struct fw_store *fw_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BANKED_FW_STORE_H */
diff --git a/components/service/fwu/fw_store/banked/component.cmake b/components/service/fwu/fw_store/banked/component.cmake
new file mode 100644
index 000000000..2eaafced4
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/component.cmake
@@ -0,0 +1,15 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/banked_fw_store.c"
+ "${CMAKE_CURRENT_LIST_DIR}/metadata_manager.c"
+ "${CMAKE_CURRENT_LIST_DIR}/bank_tracker.c"
+ )
diff --git a/components/service/fwu/fw_store/banked/metadata_manager.c b/components/service/fwu/fw_store/banked/metadata_manager.c
new file mode 100644
index 000000000..954dcc960
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_manager.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "metadata_manager.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/crc32/crc32.h"
+#include "media/volume/index/volume_index.h"
+#include "media/volume/volume.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h"
+#include "trace.h"
+#include "volume_id.h"
+
+static int load_and_check_metadata(struct volume *volume, uint8_t *buf, size_t expected_len)
+{
+ int status = FWU_STATUS_UNKNOWN;
+
+ status = volume_open(volume);
+
+ if (status == 0) {
+ size_t len = 0;
+
+ status = volume_read(volume, (uintptr_t)buf, expected_len, &len);
+
+ if (status == 0) {
+ uint32_t calc_crc =
+ crc32(0U, buf + sizeof(uint32_t), expected_len - sizeof(uint32_t));
+
+ uint32_t expected_crc = *((uint32_t *)buf);
+
+ status = (calc_crc == expected_crc) ? FWU_STATUS_SUCCESS :
+ FWU_STATUS_UNKNOWN;
+ }
+
+ volume_close(volume);
+ }
+
+ return status;
+}
+
+static int store_metadata(struct volume *volume, const uint8_t *data, size_t data_len)
+{
+ int status = volume_open(volume);
+
+ if (status == 0) {
+ status = volume_erase(volume);
+
+ if (status == 0) {
+ size_t written_len = 0;
+
+ status =
+ volume_write(volume, (const uintptr_t)data, data_len, &written_len);
+ }
+
+ volume_close(volume);
+ }
+
+ return status;
+}
+
+int metadata_manager_init(struct metadata_manager *subject,
+ const struct metadata_serializer *serializer)
+{
+ assert(subject);
+ assert(serializer);
+
+ subject->serializer = serializer;
+
+ /* Depending on the class of device, the storage volumes that hold FWU
+ * metadata may or may not be accessible by the metadata_manager. This
+ * should be reflected by which volumes have been added to the volume_index
+ * by deployment specific configuration code.
+ */
+ subject->primary_metadata_volume = NULL;
+ subject->backup_metadata_volume = NULL;
+
+ volume_index_find(BANKED_VOLUME_ID_PRIMARY_METADATA, &subject->primary_metadata_volume);
+ volume_index_find(BANKED_VOLUME_ID_BACKUP_METADATA, &subject->backup_metadata_volume);
+
+ /* A cached copy of the metadata is held in memory. It will not initially
+ * hold a valid copy until one has been loaded from storage or a fresh
+ * version has been written.
+ */
+ subject->is_dirty = false;
+ subject->is_valid = false;
+ subject->stored_crc = 0;
+ subject->metadata_len = 0;
+ subject->metadata_max_len = subject->serializer->max_size();
+ subject->metadata_cache = malloc(subject->metadata_max_len);
+
+ return (subject->metadata_cache) ? FWU_STATUS_SUCCESS : FWU_STATUS_UNKNOWN;
+}
+
+void metadata_manager_deinit(struct metadata_manager *subject)
+{
+ free(subject->metadata_cache);
+}
+
+int metadata_manager_check_and_repair(struct metadata_manager *subject,
+ const struct fw_directory *fw_dir)
+{
+ int primary_status = FWU_STATUS_UNKNOWN;
+ int backup_status = FWU_STATUS_UNKNOWN;
+
+ /* No need to perform operation if valid data is already held.*/
+ if (subject->is_valid)
+ return FWU_STATUS_SUCCESS;
+
+ /* If no storage volume is accessible (e.g. with a single flash configuration),
+ * the operation can never succeed.
+ */
+ if (!subject->primary_metadata_volume && !subject->backup_metadata_volume) {
+ IMSG("FWU volume not accessible");
+ return FWU_STATUS_UNKNOWN;
+ }
+
+ /* Loaded metadata length should be consistent with the view of firmware held
+ * by the fw_directory.
+ */
+ subject->metadata_len = subject->serializer->size(fw_dir);
+
+ if (subject->primary_metadata_volume) {
+ primary_status = load_and_check_metadata(subject->primary_metadata_volume,
+ subject->metadata_cache,
+ subject->metadata_len);
+
+ subject->is_valid = (primary_status == FWU_STATUS_SUCCESS);
+ }
+
+ if (subject->backup_metadata_volume) {
+ if (subject->is_valid) {
+ /* Already successfully loaded the primary copy. Just need to check
+ * the backup and repair it if necessary. During an update operation,
+ * the primary metadata is always written first. A hazard exists where
+ * both primary and backup are valid but they contain different data
+ * due to a power failure just before writing the backup. This
+ * condition needs to be checked for.
+ */
+ uint8_t *backup_buf = malloc(subject->metadata_len);
+
+ if (backup_buf) {
+ backup_status =
+ load_and_check_metadata(subject->backup_metadata_volume,
+ backup_buf, subject->metadata_len);
+
+ if ((backup_status == FWU_STATUS_SUCCESS) &&
+ (*(uint32_t *)backup_buf !=
+ *(uint32_t *)subject->metadata_cache)) {
+ /* Both copies have valid CRC but CRSs are different. Force
+ * the backup to be repaired.
+ */
+ backup_status = FWU_STATUS_UNKNOWN;
+ }
+
+ free(backup_buf);
+ }
+ } else {
+ /* Primary must have failed so use the backup copy. */
+ backup_status = load_and_check_metadata(subject->backup_metadata_volume,
+ subject->metadata_cache,
+ subject->metadata_len);
+
+ subject->is_valid = (backup_status == FWU_STATUS_SUCCESS);
+ }
+ }
+
+ /* Attempt a repair if necessary (and possible) */
+ if (subject->is_valid) {
+ if ((primary_status != FWU_STATUS_SUCCESS) && subject->primary_metadata_volume) {
+ IMSG("Repairing primary FWU metadata");
+
+ primary_status = store_metadata(subject->primary_metadata_volume,
+ subject->metadata_cache,
+ subject->metadata_len);
+ }
+
+ if ((backup_status != FWU_STATUS_SUCCESS) && subject->backup_metadata_volume) {
+ IMSG("Repairing backup FWU metadata");
+
+ backup_status = store_metadata(subject->backup_metadata_volume,
+ subject->metadata_cache,
+ subject->metadata_len);
+ }
+ }
+
+ /* Synchronize the view of the stored CRC */
+ if (subject->is_valid)
+ subject->stored_crc = *(uint32_t *)subject->metadata_cache;
+
+ return (subject->is_valid) ? FWU_STATUS_SUCCESS : FWU_STATUS_UNKNOWN;
+}
+
+int metadata_manager_update(struct metadata_manager *subject, uint32_t active_index,
+ uint32_t previous_active_index, const struct fw_directory *fw_dir,
+ const struct bank_tracker *bank_tracker)
+{
+ int primary_status = FWU_STATUS_SUCCESS;
+ int backup_status = FWU_STATUS_SUCCESS;
+
+ subject->metadata_len = subject->serializer->size(fw_dir);
+
+ /* Serialize metadata into metadata cache */
+ subject->serializer->serialize(active_index, previous_active_index, fw_dir, bank_tracker,
+ subject->metadata_cache, subject->metadata_max_len,
+ &subject->metadata_len);
+
+ /* Update cache copy with valid crc */
+ uint32_t calc_crc = crc32(0U, subject->metadata_cache + sizeof(uint32_t),
+ subject->metadata_len - sizeof(uint32_t));
+ *(uint32_t *)subject->metadata_cache = calc_crc;
+
+ bool was_valid = subject->is_valid;
+
+ /* Cache has been updated so it now holds valid data */
+ subject->is_valid = true;
+ subject->is_dirty = true;
+
+ /* To prevent unnecessary flash writes, if after serialization, there
+ * is no change to the metadata, skip the store operation.
+ */
+ if (was_valid && (subject->stored_crc == *(uint32_t *)subject->metadata_cache))
+ return FWU_STATUS_SUCCESS;
+
+ /* Update NV storage - order of primary followed by backup is important to
+ * defend against a power failure after updating the primary but before the backup.
+ */
+ if (subject->primary_metadata_volume) {
+ primary_status = store_metadata(subject->primary_metadata_volume,
+ subject->metadata_cache, subject->metadata_len);
+ }
+
+ if (subject->backup_metadata_volume) {
+ backup_status = store_metadata(subject->backup_metadata_volume,
+ subject->metadata_cache, subject->metadata_len);
+ }
+
+ /* Updated the view of the stored data if successfully stored */
+ if ((primary_status == FWU_STATUS_SUCCESS) && (backup_status == FWU_STATUS_SUCCESS))
+ subject->stored_crc = *(uint32_t *)subject->metadata_cache;
+
+ return (primary_status != FWU_STATUS_SUCCESS) ? primary_status :
+ (backup_status != FWU_STATUS_SUCCESS) ? backup_status :
+ FWU_STATUS_SUCCESS;
+}
+
+int metadata_manager_fetch(struct metadata_manager *subject, const uint8_t **data, size_t *data_len,
+ bool *is_dirty)
+{
+ int status = FWU_STATUS_UNKNOWN;
+
+ if (subject->is_valid) {
+ *data = subject->metadata_cache;
+ *data_len = subject->metadata_len;
+ *is_dirty = subject->is_dirty;
+
+ subject->is_dirty = false;
+
+ status = FWU_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+int metadata_manager_get_active_indices(const struct metadata_manager *subject,
+ uint32_t *active_index, uint32_t *previous_active_index)
+{
+ int status = FWU_STATUS_UNKNOWN;
+
+ if (subject->is_valid) {
+ subject->serializer->deserialize_active_indices(active_index, previous_active_index,
+ subject->metadata_cache,
+ subject->metadata_len);
+
+ status = FWU_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+void metadata_manager_cache_invalidate(struct metadata_manager *subject)
+{
+ subject->is_valid = false;
+}
+
+void metadata_manager_preload_bank_tracker(const struct metadata_manager *subject,
+ struct bank_tracker *bank_tracker)
+{
+ subject->serializer->deserialize_bank_info(bank_tracker, subject->metadata_cache,
+ subject->metadata_len);
+}
diff --git a/components/service/fwu/fw_store/banked/metadata_manager.h b/components/service/fwu/fw_store/banked/metadata_manager.h
new file mode 100644
index 000000000..684105745
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_manager.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef METADATA_MANAGER_H
+#define METADATA_MANAGER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct volume;
+struct fw_directory;
+struct bank_tracker;
+struct metadata_serializer;
+
+/**
+ * \brief metadata_manager structure definition
+ *
+ * Manages the FWU metadata seen by the boot loader.
+ */
+struct metadata_manager {
+ /* Volume objects for IO operations to NV storage */
+ struct volume *primary_metadata_volume;
+ struct volume *backup_metadata_volume;
+
+ /* Metadata serializer compatible with bootloader */
+ const struct metadata_serializer *serializer;
+
+ /* Cached copy of metadata */
+ bool is_dirty;
+ bool is_valid;
+ uint32_t stored_crc;
+ size_t metadata_len;
+ size_t metadata_max_len;
+ uint8_t *metadata_cache;
+};
+
+/**
+ * \brief Initialize the metadata_manager
+ *
+ * \param[in] subject This instance
+ * \param[in] serializer Metadata serializer to use
+ *
+ * \return Status 0 on success
+ */
+int metadata_manager_init(struct metadata_manager *subject,
+ const struct metadata_serializer *serializer);
+
+/**
+ * \brief De-initialize the metadata_manager
+ *
+ * \param[in] subject This instance
+ */
+void metadata_manager_deinit(struct metadata_manager *subject);
+
+/**
+ * \brief Check integrity of FWU metadata and repair if necessary
+ *
+ * FWU metadata is vulnerable to corruption due to power failure during a
+ * write to storage. To mitigate this risk, a replica is maintained which
+ * the boot loader will use if necessary. When a corruption occurs, the
+ * corrupted copy is repaired by copying the intact replica. Returns
+ * failure if a repair was not possible.
+ *
+ * \param[in] subject This instance
+ * \param[in] fw_dir The fw_directory
+ *
+ * \return Status 0 if intact or if repair was successful
+ */
+int metadata_manager_check_and_repair(struct metadata_manager *subject,
+ const struct fw_directory *fw_dir);
+
+/**
+ * \brief Update the FWU metadata seen by the boot loader
+ *
+ * \param[in] subject This instance
+ * \param[in] active_index The active bank index
+ * \param[in] previous_active_index The previous active bank index
+ * \param[in] fw_dir Source firmware directory
+ * \param[in] bank_tracker Provides bank state
+ *
+ * \return Status 0 if successful
+ */
+int metadata_manager_update(struct metadata_manager *subject, uint32_t active_index,
+ uint32_t previous_active_index, const struct fw_directory *fw_dir,
+ const struct bank_tracker *bank_tracker);
+
+/**
+ * \brief Get the active index values from the metadata
+ *
+ * \param[in] subject This instance
+ * \param[out] active_index The active bank index
+ * \param[out] previous_active_index The previous active bank index
+ *
+ * \return Status 0 if successful
+ */
+int metadata_manager_get_active_indices(const struct metadata_manager *subject,
+ uint32_t *active_index, uint32_t *previous_active_index);
+
+/**
+ * \brief Fetch the FWU metadata that should be seen by the boot loader
+ *
+ * In deployments where the metadata manager is unable to update the metadata
+ * seen by the boot loader directly, this function outputs the most recently
+ * updated view of the metadata to enable a Nwd component to perform the necessary
+ * write to storage.
+ *
+ * \param[in] subject This instance
+ * \param[out] data Outputs pointer to data
+ * \param[out] data_len Length of metadata
+ * \param[out] is_dirty True if updated since previous call
+ *
+ * \return Status 0 if successful
+ */
+int metadata_manager_fetch(struct metadata_manager *subject, const uint8_t **data, size_t *data_len,
+ bool *is_dirty);
+
+/**
+ * \brief Invalidate the metadata cache
+ *
+ * \param[in] subject This instance
+ */
+void metadata_manager_cache_invalidate(struct metadata_manager *subject);
+
+/**
+ * \brief Preload the bank_tracker with NV state from metadata
+ *
+ * \param[in] subject This instance
+ * \param[in] bank_tracker The bank_tracker to modify
+ *
+ * \return Status 0 if successful
+ */
+void metadata_manager_preload_bank_tracker(const struct metadata_manager *subject,
+ struct bank_tracker *bank_tracker);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* METADATA_MANAGER_H */
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h b/components/service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h
new file mode 100644
index 000000000..3d2818128
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef METADATA_SERIALIZER_H
+#define METADATA_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct fw_directory;
+struct bank_tracker;
+
+/**
+ * \brief FWU metadata serializer interface
+ *
+ * Defines a common interface for FWU serialization operations. Because
+ * updates to the bootloader and update agent are likely to occur at different
+ * times, it is necessary for the update agent to have some agility over the
+ * metadata version that it generates in order to maintain compatibility with
+ * the bootloader. The active serializer is selected based on the version
+ * reported by the bootloader at boot time. Note that the early stage bootloader
+ * that interprets the metadata cannot be updated using the banked update
+ * mechanism so it is not possible to rely on a simultaneous update strategy.
+ * To provide a pathway for transitioning to a new metadata version,
+ * support for runtime selection of the metadata serializer is possible.
+ */
+struct metadata_serializer {
+ /**
+ * \brief Serialize FWU metadata
+ *
+ * Serialize FWU metadata using the presented inputs.
+ *
+ * \param[in] active_index The active bank index
+ * \param[in] previous_active_index The previous active bank index
+ * \param[in] fw_dir Source firmware directory
+ * \param[in] bank_tracker source bank_tracker
+ * \param[in] buf Serialize into this buffer
+ * \param[in] buf_size Size of buffer
+ * \param[out] metadata_len Size of serialized metadata
+ *
+ * \return Status
+ */
+ int (*serialize)(uint32_t active_index, uint32_t previous_active_index,
+ const struct fw_directory *fw_dir, const struct bank_tracker *bank_tracker,
+ uint8_t *buf, size_t buf_size, size_t *metadata_len);
+
+ /**
+ * \brief Return serialized FWU metadata size
+ *
+ * \param[in] fw_dir Source information
+ *
+ * \return Size in bytes
+ */
+ size_t (*size)(const struct fw_directory *fw_dir);
+
+ /**
+ * \brief Return the maximum serialized FWU metadata size
+ *
+ * \return Size in bytes
+ */
+ size_t (*max_size)(void);
+
+ /**
+ * \brief De-serialize bank info information
+ *
+ * \param[in] bank_tracker Destination bank_tracker
+ * \param[in] serialized_metadata Serialized metadata
+ * \param[in] metadata_len Length of serialized metadata
+ */
+ void (*deserialize_bank_info)(struct bank_tracker *bank_tracker,
+ const uint8_t *serialized_metadata, size_t metadata_len);
+
+ /**
+ * \brief De-serialize active indices
+ *
+ * \param[out] active_index active_index value
+ * \param[out] previous_active_index previous_active_index value
+ * \param[in] serialized_metadata Serialized metadata
+ * \param[in] metadata_len Length of serialized metadata
+ */
+ void (*deserialize_active_indices)(uint32_t *active_index, uint32_t *previous_active_index,
+ const uint8_t *serialized_metadata, size_t metadata_len);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* METADATA_SERIALIZER_H */
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v1/component.cmake b/components/service/fwu/fw_store/banked/metadata_serializer/v1/component.cmake
new file mode 100644
index 000000000..17c50f192
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v1/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/metadata_serializer_v1.c"
+ )
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.c b/components/service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.c
new file mode 100644
index 000000000..5458b4ca4
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "metadata_serializer_v1.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "common/uuid/uuid.h"
+#include "media/volume/index/volume_index.h"
+#include "media/volume/volume.h"
+#include "protocols/service/fwu/packed-c/metadata_v1.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/agent/fw_directory.h"
+#include "service/fwu/fw_store/banked/bank_tracker.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+
+static int serialize_image_entries(struct fwu_metadata *metadata, const struct fw_directory *fw_dir,
+ const struct bank_tracker *bank_tracker)
+{
+ size_t image_index = 0;
+
+ do {
+ /* Image entry indices in the metadata correspond to the image index
+ * of the associate entry in the fw_directory.
+ */
+ const struct image_info *image_info =
+ fw_directory_get_image_info(fw_dir, image_index);
+
+ if (!image_info)
+ break;
+
+ /* Information about storage for the image is retrieved from the configured
+ * volume objects that provide access to the banked storage. Both volumes
+ * are assumed to have the same parent location, identified by the location
+ * uuid.
+ */
+ struct uuid_octets location_uuid = { 0 };
+ struct fwu_image_entry *entry = &metadata->img_entry[image_index];
+
+ /* Serialize bank storage info */
+ for (size_t bank_index = 0; bank_index < BANK_SCHEME_NUM_BANKS; bank_index++) {
+ struct uuid_octets img_uuid = { 0 };
+ struct volume *volume = NULL;
+
+ int status =
+ volume_index_find(banked_volume_id(image_info->location_id,
+ banked_usage_id(bank_index)),
+ &volume);
+
+ if (!status && volume)
+ volume_get_storage_ids(volume, &img_uuid, &location_uuid);
+
+ struct fwu_image_properties *properties = &entry->img_props[bank_index];
+
+ memcpy(properties->img_uuid, img_uuid.octets, OSF_UUID_OCTET_LEN);
+ properties->reserved = 0;
+ properties->accepted =
+ bank_tracker_is_accepted(bank_tracker, bank_index, image_index) ?
+ 1 :
+ 0;
+ }
+
+ /* Serialize per-image UUIDs */
+ memcpy(entry->img_type_uuid, image_info->img_type_uuid.octets, OSF_UUID_OCTET_LEN);
+ memcpy(entry->location_uuid, location_uuid.octets, OSF_UUID_OCTET_LEN);
+
+ ++image_index;
+
+ } while (true);
+
+ return FWU_STATUS_SUCCESS;
+}
+
+static size_t metadata_serializer_size(const struct fw_directory *fw_dir)
+{
+ return offsetof(struct fwu_metadata, img_entry) +
+ fw_directory_num_images(fw_dir) * sizeof(struct fwu_image_entry);
+}
+
+static size_t metadata_serializer_max_size(void)
+{
+ return offsetof(struct fwu_metadata, img_entry) +
+ FWU_MAX_FW_DIRECTORY_ENTRIES * sizeof(struct fwu_image_entry);
+}
+
+static int metadata_serializer_serialize(uint32_t active_index, uint32_t previous_active_index,
+ const struct fw_directory *fw_dir,
+ const struct bank_tracker *bank_tracker, uint8_t *buf,
+ size_t buf_size, size_t *metadata_len)
+{
+ int status = FWU_STATUS_UNKNOWN;
+ size_t serialized_size = metadata_serializer_size(fw_dir);
+
+ *metadata_len = 0;
+
+ if (serialized_size <= buf_size) {
+ struct fwu_metadata *metadata = (struct fwu_metadata *)buf;
+
+ /* Serialize metadata header */
+ metadata->crc_32 = 0;
+ metadata->version = FWU_METADATA_VERSION;
+ metadata->active_index = active_index;
+ metadata->previous_active_index = previous_active_index;
+
+ /* Serialize image entries */
+ status = serialize_image_entries(metadata, fw_dir, bank_tracker);
+
+ if (status == FWU_STATUS_SUCCESS)
+ *metadata_len = serialized_size;
+ }
+
+ return status;
+}
+
+static void metadata_serializer_deserialize_bank_info(struct bank_tracker *bank_tracker,
+ const uint8_t *serialized_metadata,
+ size_t metadata_len)
+{
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)serialized_metadata;
+
+ /* Assume referenced banks hold content */
+ if (metadata->active_index < BANK_SCHEME_NUM_BANKS)
+ bank_tracker_set_holds_content(bank_tracker, metadata->active_index);
+
+ if (metadata->previous_active_index < BANK_SCHEME_NUM_BANKS)
+ bank_tracker_set_holds_content(bank_tracker, metadata->previous_active_index);
+
+ /* Deserialize image accept state */
+ if (metadata_len >= offsetof(struct fwu_metadata, img_entry)) {
+ size_t num_images = (metadata_len - offsetof(struct fwu_metadata, img_entry)) /
+ sizeof(struct fwu_image_entry);
+
+ for (size_t image_index = 0; image_index < num_images; image_index++) {
+ const struct fwu_image_entry *image_entry =
+ &metadata->img_entry[image_index];
+
+ for (size_t bank_index = 0; bank_index < BANK_SCHEME_NUM_BANKS;
+ bank_index++) {
+ if (image_entry->img_props[bank_index].accepted)
+ bank_tracker_accept(bank_tracker, bank_index, image_index);
+ }
+ }
+ }
+}
+
+static void metadata_serializer_deserialize_active_indices(uint32_t *active_index,
+ uint32_t *previous_active_index,
+ const uint8_t *serialized_metadata,
+ size_t metadata_len)
+{
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)serialized_metadata;
+
+ assert(metadata_len >= offsetof(struct fwu_metadata, img_entry));
+
+ *active_index = metadata->active_index;
+ *previous_active_index = metadata->previous_active_index;
+}
+
+const struct metadata_serializer *metadata_serializer_v1(void)
+{
+ static const struct metadata_serializer serializer = {
+ metadata_serializer_serialize, metadata_serializer_size,
+ metadata_serializer_max_size, metadata_serializer_deserialize_bank_info,
+ metadata_serializer_deserialize_active_indices
+ };
+
+ return &serializer;
+}
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h b/components/service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h
new file mode 100644
index 000000000..e64712b58
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef METADATA_SERIALIZER_V1_H
+#define METADATA_SERIALIZER_V1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct metadata_serializer;
+
+/**
+ * \brief Return a metadata_serializer for version 1 serialization
+ *
+ */
+const struct metadata_serializer *metadata_serializer_v1(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* METADATA_SERIALIZER_V1_H */
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v2/component.cmake b/components/service/fwu/fw_store/banked/metadata_serializer/v2/component.cmake
new file mode 100644
index 000000000..1a274e321
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v2/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/metadata_serializer_v2.c"
+ )
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.c b/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.c
new file mode 100644
index 000000000..1ef61e486
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "metadata_serializer_v2.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "common/uuid/uuid.h"
+#include "media/volume/index/volume_index.h"
+#include "media/volume/volume.h"
+#include "protocols/service/fwu/packed-c/metadata_v2.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/agent/fw_directory.h"
+#include "service/fwu/fw_store/banked/bank_tracker.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+
+static size_t metadata_serializer_size(const struct fw_directory *fw_dir)
+{
+ return sizeof(struct fwu_metadata) + offsetof(struct fwu_fw_store_desc, img_entry) +
+ sizeof(struct fwu_image_entry) * fw_directory_num_images(fw_dir);
+}
+
+static size_t metadata_serializer_max_size(void)
+{
+ return sizeof(struct fwu_metadata) + offsetof(struct fwu_fw_store_desc, img_entry) +
+ sizeof(struct fwu_image_entry) * FWU_MAX_FW_DIRECTORY_ENTRIES;
+}
+
+static int serialize_image_entries(struct fwu_fw_store_desc *fw_store_desc,
+ const struct fw_directory *fw_dir,
+ const struct bank_tracker *bank_tracker)
+{
+ for (size_t image_index = 0; image_index < fw_store_desc->num_images; image_index++) {
+ /* Image entry indices in the fw_store_desc correspond to the image index
+ * of the associate entry in the fw_directory.
+ */
+ const struct image_info *image_info =
+ fw_directory_get_image_info(fw_dir, image_index);
+
+ assert(image_info);
+
+ /* Information about storage for the image is retrieved from the configured
+ * volume objects that provide access to the banked storage. Both volumes
+ * are assumed to have the same parent location, identified by the location
+ * uuid.
+ */
+ struct uuid_octets location_uuid = { 0 };
+ struct fwu_image_entry *entry = &fw_store_desc->img_entry[image_index];
+
+ /* Serialize bank storage info */
+ for (size_t bank_index = 0; bank_index < BANK_SCHEME_NUM_BANKS; bank_index++) {
+ struct uuid_octets img_uuid = { 0 };
+ struct volume *volume = NULL;
+
+ int status =
+ volume_index_find(banked_volume_id(image_info->location_id,
+ banked_usage_id(bank_index)),
+ &volume);
+
+ if (!status && volume) {
+ /* A concrete volume may not support retrieving storage IDs. If
+ * this is the case, volume_get_storage_ids() will return an error,
+ * which is deliberately ignored and UUIDs left in their default state.
+ * To ensure that all banks reflect the same parent location, the
+ * location uuid returned by the volume holding the first bank is
+ * used as the parent.
+ */
+ struct uuid_octets *parent_uuid =
+ (bank_index == 0) ? &location_uuid : NULL;
+
+ volume_get_storage_ids(volume, &img_uuid, parent_uuid);
+ }
+
+ struct fwu_img_bank_info *bank_info = &entry->img_bank_info[bank_index];
+
+ memcpy(bank_info->img_uuid, img_uuid.octets, OSF_UUID_OCTET_LEN);
+ bank_info->reserved = 0;
+ bank_info->accepted =
+ bank_tracker_is_accepted(bank_tracker, bank_index, image_index) ?
+ 1 :
+ 0;
+ }
+
+ /* Serialize per-image UUIDs */
+ memcpy(entry->img_type_uuid, image_info->img_type_uuid.octets, OSF_UUID_OCTET_LEN);
+ memcpy(entry->location_uuid, location_uuid.octets, OSF_UUID_OCTET_LEN);
+ }
+
+ return FWU_STATUS_SUCCESS;
+}
+
+static int serialize_fw_store_desc(const struct fw_directory *fw_dir,
+ const struct bank_tracker *bank_tracker, uint8_t *buf)
+{
+ struct fwu_fw_store_desc *fw_store_desc = (struct fwu_fw_store_desc *)buf;
+
+ fw_store_desc->num_banks = BANK_SCHEME_NUM_BANKS;
+ fw_store_desc->num_images = fw_directory_num_images(fw_dir);
+ fw_store_desc->img_entry_size = sizeof(struct fwu_image_entry);
+ fw_store_desc->bank_entry_size = sizeof(struct fwu_img_bank_info);
+
+ return serialize_image_entries(fw_store_desc, fw_dir, bank_tracker);
+}
+
+static int metadata_serializer_serialize(uint32_t active_index, uint32_t previous_active_index,
+ const struct fw_directory *fw_dir,
+ const struct bank_tracker *bank_tracker, uint8_t *buf,
+ size_t buf_size, size_t *metadata_len)
+{
+ int status = FWU_STATUS_UNKNOWN;
+ size_t serialized_size = metadata_serializer_size(fw_dir);
+
+ *metadata_len = 0;
+
+ if (serialized_size <= buf_size) {
+ struct fwu_metadata *metadata = (struct fwu_metadata *)buf;
+
+ /* Serialize metadata header */
+ metadata->crc_32 = 0;
+ metadata->version = 2;
+ metadata->metadata_size = (uint32_t)serialized_size;
+ metadata->header_size = (uint16_t)sizeof(struct fwu_metadata);
+ metadata->active_index = active_index;
+ metadata->previous_active_index = previous_active_index;
+
+ for (unsigned int bank_index = 0; bank_index < FWU_METADATA_V2_NUM_BANK_STATES;
+ bank_index++) {
+ if (bank_index < BANK_SCHEME_NUM_BANKS) {
+ if (bank_tracker_is_all_accepted(bank_tracker, bank_index,
+ fw_directory_num_images(fw_dir)))
+ metadata->bank_state[bank_index] =
+ FWU_METADATA_V2_BANK_STATE_ACCEPTED;
+ else if (bank_tracker_is_content(bank_tracker, bank_index))
+ metadata->bank_state[bank_index] =
+ FWU_METADATA_V2_BANK_STATE_VALID;
+ else
+ metadata->bank_state[bank_index] =
+ FWU_METADATA_V2_BANK_STATE_INVALID;
+
+ } else
+ metadata->bank_state[bank_index] =
+ FWU_METADATA_V2_BANK_STATE_INVALID;
+ }
+
+ /* Serialize optional fw store descriptor if required */
+ if (serialized_size > metadata->header_size)
+ status = serialize_fw_store_desc(fw_dir, bank_tracker,
+ &buf[metadata->header_size]);
+ else
+ status = FWU_STATUS_SUCCESS;
+
+ if (status == FWU_STATUS_SUCCESS)
+ *metadata_len = serialized_size;
+ }
+
+ return status;
+}
+
+static void metadata_serializer_deserialize_bank_info(struct bank_tracker *bank_tracker,
+ const uint8_t *serialized_metadata,
+ size_t metadata_len)
+{
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)serialized_metadata;
+
+ /* Sanity check size values in header */
+ if ((metadata->header_size > metadata_len) || (metadata->metadata_size > metadata_len))
+ return;
+
+ /* Deserialize bank state in header and update bank_tracker to reflect the same state */
+ for (unsigned int bank_index = 0; bank_index < BANK_SCHEME_NUM_BANKS; bank_index++) {
+ if (metadata->bank_state[bank_index] == FWU_METADATA_V2_BANK_STATE_ACCEPTED)
+ bank_tracker_set_holds_accepted_content(bank_tracker, bank_index);
+ else if (metadata->bank_state[bank_index] == FWU_METADATA_V2_BANK_STATE_VALID)
+ bank_tracker_set_holds_content(bank_tracker, bank_index);
+ }
+
+ /* If present, deserialize the fw_store_desc */
+ if (metadata->metadata_size >=
+ metadata->header_size + offsetof(struct fwu_fw_store_desc, img_entry)) {
+ const struct fwu_fw_store_desc *fw_store_desc =
+ (const struct fwu_fw_store_desc *)(serialized_metadata +
+ metadata->header_size);
+
+ size_t fw_store_desc_size = metadata->metadata_size - metadata->header_size;
+ size_t total_img_entries_size =
+ fw_store_desc_size - offsetof(struct fwu_fw_store_desc, img_entry);
+ size_t per_img_entry_bank_info_size =
+ fw_store_desc->num_banks * fw_store_desc->bank_entry_size;
+
+ /* Sanity check fw_store_desc values */
+ if ((fw_store_desc->img_entry_size < sizeof(struct fwu_image_entry)) ||
+ (fw_store_desc->bank_entry_size < sizeof(struct fwu_img_bank_info)) ||
+ (fw_store_desc->num_banks > BANK_SCHEME_NUM_BANKS) ||
+ (fw_store_desc->img_entry_size <
+ offsetof(struct fwu_image_entry, img_bank_info) +
+ per_img_entry_bank_info_size) ||
+ (fw_store_desc->num_images > FWU_MAX_FW_DIRECTORY_ENTRIES) ||
+ (total_img_entries_size <
+ fw_store_desc->num_images * fw_store_desc->img_entry_size))
+ return;
+
+ /* Deserialize per-image info */
+ for (size_t image_index = 0; image_index < fw_store_desc->num_images;
+ image_index++) {
+ const struct fwu_image_entry *image_entry =
+ (const struct fwu_image_entry
+ *)((const uint8_t *)fw_store_desc->img_entry +
+ image_index * fw_store_desc->img_entry_size);
+
+ for (size_t bank_index = 0; bank_index < fw_store_desc->num_banks;
+ bank_index++) {
+ const struct fwu_img_bank_info *bank_info =
+ (const struct fwu_img_bank_info
+ *)((const uint8_t *)image_entry->img_bank_info +
+ bank_index * fw_store_desc->bank_entry_size);
+
+ if (bank_info->accepted)
+ bank_tracker_accept(bank_tracker, bank_index, image_index);
+ }
+ }
+ }
+}
+
+static void metadata_serializer_deserialize_active_indices(uint32_t *active_index,
+ uint32_t *previous_active_index,
+ const uint8_t *serialized_metadata,
+ size_t metadata_len)
+{
+ const struct fwu_metadata *metadata = (const struct fwu_metadata *)serialized_metadata;
+
+ assert(metadata_len >= sizeof(struct fwu_metadata));
+
+ *active_index = metadata->active_index;
+ *previous_active_index = metadata->previous_active_index;
+}
+
+const struct metadata_serializer *metadata_serializer_v2(void)
+{
+ static const struct metadata_serializer serializer = {
+ metadata_serializer_serialize, metadata_serializer_size,
+ metadata_serializer_max_size, metadata_serializer_deserialize_bank_info,
+ metadata_serializer_deserialize_active_indices
+ };
+
+ return &serializer;
+}
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h b/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h
new file mode 100644
index 000000000..c095cc92a
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef METADATA_SERIALIZER_V2_H
+#define METADATA_SERIALIZER_V2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct metadata_serializer;
+
+/**
+ * \brief Return a metadata_serializer for version 2 serialization
+ *
+ */
+const struct metadata_serializer *metadata_serializer_v2(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* METADATA_SERIALIZER_V2_H */
diff --git a/components/service/fwu/fw_store/banked/test/component.cmake b/components/service/fwu/fw_store/banked/test/component.cmake
new file mode 100644
index 000000000..2e5bb8ed4
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/test/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/metadata_manager_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/metadata_v2_tests.cpp"
+ )
diff --git a/components/service/fwu/fw_store/banked/test/metadata_manager_tests.cpp b/components/service/fwu/fw_store/banked/test/metadata_manager_tests.cpp
new file mode 100644
index 000000000..5295be36d
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/test/metadata_manager_tests.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <stdlib.h>
+
+#include "common/uuid/uuid.h"
+#include "media/disk/guid.h"
+#include "media/volume/block_volume/block_volume.h"
+#include "media/volume/index/volume_index.h"
+#include "media/volume/volume.h"
+#include "service/block_storage/factory/ref_ram_gpt/block_store_factory.h"
+#include "service/fwu/agent/fw_directory.h"
+#include "service/fwu/fw_store/banked/bank_tracker.h"
+#include "service/fwu/fw_store/banked/metadata_manager.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+#include "service/fwu/inspector/mock/mock_fw_inspector.h"
+
+TEST_GROUP(FwuMetadataManagerTests)
+{
+ void setup()
+ {
+ int result;
+ struct uuid_octets partition_guid;
+
+ /* Default to V1 metadata serializer */
+ m_serializer = metadata_serializer_v1();
+
+ /* Construct storage */
+ volume_index_init();
+ m_block_store = ref_ram_gpt_block_store_factory_create();
+
+ /* Construct primary metadata volume */
+ uuid_guid_octets_from_canonical(&partition_guid,
+ DISK_GUID_UNIQUE_PARTITION_PRIMARY_FWU_METADATA);
+
+ result = block_volume_init(&m_primary_block_volume, m_block_store, &partition_guid,
+ &m_primary_volume);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_primary_volume);
+
+ /* Construct backup metadata volume */
+ uuid_guid_octets_from_canonical(&partition_guid,
+ DISK_GUID_UNIQUE_PARTITION_BACKUP_FWU_METADATA);
+
+ result = block_volume_init(&m_backup_block_volume, m_block_store, &partition_guid,
+ &m_backup_volume);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_backup_volume);
+
+ bank_tracker_init(&m_bank_tracker);
+ fw_directory_init(&m_fw_directory);
+
+ result = mock_fw_inspector_inspect(&m_fw_directory, BOOT_INDEX);
+ LONGS_EQUAL(0, result);
+ }
+
+ void teardown()
+ {
+ metadata_manager_deinit(&m_metadata_manager);
+ fw_directory_deinit(&m_fw_directory);
+ bank_tracker_deinit(&m_bank_tracker);
+
+ volume_index_clear();
+ block_volume_deinit(&m_primary_block_volume);
+ block_volume_deinit(&m_backup_block_volume);
+ ref_ram_gpt_block_store_factory_destroy(m_block_store);
+ }
+
+ void corrupt_metadata(struct volume * volume)
+ {
+ int status;
+ size_t metadata_size = m_serializer->size(&m_fw_directory);
+ uint8_t metadata_buf[metadata_size];
+ size_t actual_len = 0;
+
+ status = volume_open(volume);
+ LONGS_EQUAL(0, status);
+
+ status = volume_read(volume, (uintptr_t)metadata_buf, metadata_size, &actual_len);
+ LONGS_EQUAL(0, status);
+ UNSIGNED_LONGS_EQUAL(metadata_size, actual_len);
+
+ /* Corrupt the first byte */
+ metadata_buf[0] ^= 0xff;
+
+ /* Erase contents and write back the corrupted copy */
+ status = volume_erase(volume);
+ LONGS_EQUAL(0, status);
+
+ status = volume_seek(volume, IO_SEEK_SET, 0);
+ LONGS_EQUAL(0, status);
+
+ status = volume_write(volume, (const uintptr_t)metadata_buf, metadata_size,
+ &actual_len);
+ LONGS_EQUAL(0, status);
+ UNSIGNED_LONGS_EQUAL(metadata_size, actual_len);
+
+ volume_close(volume);
+ }
+
+ static const unsigned int BOOT_INDEX = 1;
+
+ struct block_store *m_block_store;
+ struct block_volume m_primary_block_volume;
+ struct block_volume m_backup_block_volume;
+ struct volume *m_primary_volume;
+ struct volume *m_backup_volume;
+ struct metadata_manager m_metadata_manager;
+ struct fw_directory m_fw_directory;
+ struct bank_tracker m_bank_tracker;
+ const struct metadata_serializer *m_serializer;
+};
+
+TEST(FwuMetadataManagerTests, checkAndRepairAccessibleStorage)
+{
+ int result = 0;
+
+ /* Check configuration where metadata storage is accessible. Because neither
+ * metadata copy has been initialized, initially expect the check and repair
+ * operation to fail. */
+ result = volume_index_add(BANKED_VOLUME_ID_PRIMARY_METADATA, m_primary_volume);
+ LONGS_EQUAL(0, result);
+ result = volume_index_add(BANKED_VOLUME_ID_BACKUP_METADATA, m_backup_volume);
+ LONGS_EQUAL(0, result);
+
+ result = metadata_manager_init(&m_metadata_manager, m_serializer);
+ LONGS_EQUAL(0, result);
+
+ result = metadata_manager_check_and_repair(&m_metadata_manager, &m_fw_directory);
+ CHECK_TRUE(result != 0);
+
+ /* An update to the metadata should result in both primary and backup copies
+ * being initialized. */
+ result = metadata_manager_update(&m_metadata_manager, 0, 1, &m_fw_directory,
+ &m_bank_tracker);
+ LONGS_EQUAL(0, result);
+
+ /* If the update was successful, check_and_repair shouldn't have anything to do. */
+ result = metadata_manager_check_and_repair(&m_metadata_manager, &m_fw_directory);
+ LONGS_EQUAL(0, result);
+
+ /* Invalidating the cache should force a reload but expect both volumes to hold
+ * valid data.*/
+ metadata_manager_cache_invalidate(&m_metadata_manager);
+ result = metadata_manager_check_and_repair(&m_metadata_manager, &m_fw_directory);
+ LONGS_EQUAL(0, result);
+
+ /* Corrupt either copy randomly a few times and expect to always repair */
+ for (size_t i = 0; i < 100; ++i) {
+ struct volume *volume = (rand() & 1) ? m_primary_volume : m_backup_volume;
+
+ corrupt_metadata(volume);
+ metadata_manager_cache_invalidate(&m_metadata_manager);
+ result = metadata_manager_check_and_repair(&m_metadata_manager, &m_fw_directory);
+ LONGS_EQUAL(0, result);
+ }
+
+ /* Corrupt both copies - repair should not be possible */
+ corrupt_metadata(m_primary_volume);
+ corrupt_metadata(m_backup_volume);
+ metadata_manager_cache_invalidate(&m_metadata_manager);
+ result = metadata_manager_check_and_repair(&m_metadata_manager, &m_fw_directory);
+ CHECK_TRUE(result != 0);
+}
+
+TEST(FwuMetadataManagerTests, checkAndRepairInaccessibleStorage)
+{
+ int result = 0;
+
+ /* Check configuration where metadata storage is inaccessible (i.e. no
+ * volumes added to volume_index). Expect the check to fail, indicating
+ * that an update is required to initialise the cache. */
+ result = metadata_manager_init(&m_metadata_manager, m_serializer);
+ LONGS_EQUAL(0, result);
+
+ result = metadata_manager_check_and_repair(&m_metadata_manager, &m_fw_directory);
+ CHECK_TRUE(result != 0);
+} \ No newline at end of file
diff --git a/components/service/fwu/fw_store/banked/test/metadata_v2_tests.cpp b/components/service/fwu/fw_store/banked/test/metadata_v2_tests.cpp
new file mode 100644
index 000000000..7e59c6f9f
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/test/metadata_v2_tests.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <cstddef>
+
+#include "protocols/service/fwu/packed-c/metadata_v2.h"
+
+/* Tests check FWU metadata protocol definitions are aligned to the FWU-A
+ * specification.
+*/
+TEST_GROUP(FwuMetadataV2Tests){
+
+};
+
+TEST(FwuMetadataV2Tests, checkHeaderStructure)
+{
+ /* Check header structure offsets against offsets from spec */
+ UNSIGNED_LONGS_EQUAL(0x00, offsetof(fwu_metadata, crc_32));
+ UNSIGNED_LONGS_EQUAL(0x04, offsetof(fwu_metadata, version));
+ UNSIGNED_LONGS_EQUAL(0x08, offsetof(fwu_metadata, metadata_size));
+ UNSIGNED_LONGS_EQUAL(0x0c, offsetof(fwu_metadata, header_size));
+ /* Note: spec incorrectly says 0x0d - fed back */
+ UNSIGNED_LONGS_EQUAL(0x0e, offsetof(fwu_metadata, active_index));
+ UNSIGNED_LONGS_EQUAL(0x0f, offsetof(fwu_metadata, previous_active_index));
+ UNSIGNED_LONGS_EQUAL(0x10, offsetof(fwu_metadata, bank_state));
+
+ /* Check header size aligns with expected offset of optional fw_store_desc */
+ /* Note: spec incorrectly says 0x11 - fed back */
+ UNSIGNED_LONGS_EQUAL(0x14, sizeof(struct fwu_metadata));
+}
+
+TEST(FwuMetadataV2Tests, checkFwStoreDescStructure)
+{
+ /* Check fw_store_desc structure offsets against offsets from spec */
+ UNSIGNED_LONGS_EQUAL(0x00, offsetof(fwu_fw_store_desc, num_banks));
+ UNSIGNED_LONGS_EQUAL(0x01, offsetof(fwu_fw_store_desc, num_images));
+ UNSIGNED_LONGS_EQUAL(0x03, offsetof(fwu_fw_store_desc, img_entry_size));
+ UNSIGNED_LONGS_EQUAL(0x05, offsetof(fwu_fw_store_desc, bank_entry_size));
+ UNSIGNED_LONGS_EQUAL(0x07, offsetof(fwu_fw_store_desc, img_entry));
+}
+
+TEST(FwuMetadataV2Tests, checkImgEntryStructure)
+{
+ /* Check img_entry structure offsets against offsets from spec */
+ UNSIGNED_LONGS_EQUAL(0x00, offsetof(fwu_image_entry, img_type_uuid));
+ UNSIGNED_LONGS_EQUAL(0x10, offsetof(fwu_image_entry, location_uuid));
+ UNSIGNED_LONGS_EQUAL(0x20, offsetof(fwu_image_entry, img_bank_info));
+}
+
+TEST(FwuMetadataV2Tests, checkImgBankInfoStructure)
+{
+ /* Check img_entry structure offsets against offsets from spec */
+ UNSIGNED_LONGS_EQUAL(0x00, offsetof(fwu_img_bank_info, img_uuid));
+ UNSIGNED_LONGS_EQUAL(0x10, offsetof(fwu_img_bank_info, accepted));
+ UNSIGNED_LONGS_EQUAL(0x14, offsetof(fwu_img_bank_info, reserved));
+
+ /* Check img_bank_info size aligns with specified value */
+ UNSIGNED_LONGS_EQUAL(0x18, sizeof(struct fwu_img_bank_info));
+} \ No newline at end of file
diff --git a/components/service/fwu/fw_store/banked/volume_id.h b/components/service/fwu/fw_store/banked/volume_id.h
new file mode 100644
index 000000000..5776edc51
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/volume_id.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BANKED_FW_STORE_VOLUME_ID_H
+#define BANKED_FW_STORE_VOLUME_ID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Storage volume IDs used by a banked_fw_store.
+ *
+ * These IDs are used to obtain deployment specific volume objects from
+ * the volume_index to enable storage IO operations to be performed. Use
+ * of volume IDs allows generic components to be decoupled from deployment
+ * specific code. A set of volume objects will be constructed for a deployment,
+ * each configured to provide access to each area of storage that holds
+ * NV data that will be modified during the FWU process.
+ *
+ * To allow images to be installed into different storage locations (e.g.
+ * different storage partitions), a volume ID numbering scheme is used for
+ * the banked_fw_store that combines a location ID with usage ID.
+ */
+
+/* FWU metadata volume IDs. A single location is assumed. */
+#define BANKED_VOLUME_ID_PRIMARY_METADATA (0xffff0000)
+#define BANKED_VOLUME_ID_BACKUP_METADATA (0xffff0001)
+
+/* Per-location usage IDs for the banked_fw store */
+#define BANKED_USAGE_ID_FW_BANK_A (0)
+#define BANKED_USAGE_ID_FW_BANK_B (1)
+
+/**
+ * \brief Return a volume id constructed from a usage and location id
+ *
+ * Banked storage may be distributed across multiple locations. This
+ * function creates a volume ID made up of a location ID and a usage ID.
+ * A platform integrator is free define as many location IDs as is
+ * necessary to enable different areas of firmware storage to be
+ * updated. A location could correspond to say a storage partition or
+ * storage managed by a separate MCU.
+ *
+ * \param[in] location_id Platform specific location id
+ * \param[in] usage_id The requires usage for the volume
+ *
+ * \return volume id
+ */
+static inline unsigned int banked_volume_id(unsigned int location_id, unsigned int usage_id)
+{
+ return (location_id << 16) | (usage_id & 0xffff);
+}
+
+/**
+ * \brief Return the usage id for the specified bank index
+ *
+ * \param[in] bank_index The bank index [0..1]
+ *
+ * \return Usage ID
+ */
+static inline unsigned int banked_usage_id(unsigned int bank_index)
+{
+ return (bank_index == 0) ? BANKED_USAGE_ID_FW_BANK_A : BANKED_USAGE_ID_FW_BANK_B;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BANKED_FW_STORE_VOLUME_ID_H */
diff --git a/components/service/fwu/fw_store/fw_store.h b/components/service/fwu/fw_store/fw_store.h
new file mode 100644
index 000000000..1fde41a8d
--- /dev/null
+++ b/components/service/fwu/fw_store/fw_store.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FW_STORE_H
+#define FW_STORE_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct fw_store;
+struct fw_directory;
+struct image_info;
+struct installer;
+struct uuid_octets;
+
+/**
+ * \brief Synchronize fw_store state to the active state of the firmware
+ *
+ * Synchronizes the state of the fw_store to reflect the state of the
+ * booted firmware obtained from the firmware directory. The firmware directory
+ * will have been populated with information obtained from trusted
+ * sources such as the attestation service.
+ *
+ * \param[in] fw_store The subject fw_store
+ * \param[in] fw_dir The firmware directory to synchronize to
+ * \param[in] boot_index The boot_index reported by the bootloader
+ *
+ * \return FWU status code
+ */
+int fw_store_synchronize(struct fw_store *fw_store, struct fw_directory *fw_dir,
+ unsigned int boot_index);
+
+/**
+ * \brief Begin to install one or more images
+ *
+ * Should be called prior to installing one or more images into this fw_store.
+ * As long as success is returned, installation operations may follow.
+ *
+ * \param[in] fw_store The subject fw_store
+ *
+ * \return FWU status code
+ */
+int fw_store_begin_install(struct fw_store *fw_store);
+
+/**
+ * \brief Cancel any install operation in progress
+ *
+ * \param[in] fw_store The subject fw_store
+ */
+void fw_store_cancel_install(struct fw_store *fw_store);
+
+/**
+ * \brief Finalize the installation of a set of images
+ *
+ * Should be called after installing all images. Once finalized, the new
+ * installation may be activated in preparation for a trial of the update.
+ *
+ * \param[in] fw_store The subject fw_store
+ *
+ * \return FWU status code
+ */
+int fw_store_finalize_install(struct fw_store *fw_store);
+
+/**
+ * \brief Select an installer
+ *
+ * Select an installer to handle installation of the image described by
+ * the image_info.
+ *
+ * \param[in] fw_store The subject fw_store
+ * \param[in] image_info Image info that describes the image to install
+ * \param[out] installer Selected installer
+ *
+ * \return FWU status code
+ */
+int fw_store_select_installer(struct fw_store *fw_store, const struct image_info *image_info,
+ struct installer **installer);
+
+/**
+ * \brief Write image data during image installation
+ *
+ * \param[in] fw_store The subject fw_store
+ * \param[in] installer The selected installer
+ * \param[in] data Pointer to data
+ * \param[in] data_len The data length
+ *
+ * \return FWU status code
+ */
+int fw_store_write_image(struct fw_store *fw_store, struct installer *installer,
+ const uint8_t *data, size_t data_len);
+
+/**
+ * \brief Commit image data
+ *
+ * Called after fw_store_write_image to commit all image data written for an image.
+ *
+ * \param[in] fw_store The subject fw_store
+ * \param[in] installer The selected installer
+ * \param[in] image_info Info about the image
+ * \param[in] accepted Initial accepted state
+ *
+ * \return FWU status code
+ */
+int fw_store_commit_image(struct fw_store *fw_store, struct installer *installer,
+ const struct image_info *image_info, bool accepted);
+
+/**
+ * \brief Notify that an updated image has been accepted
+ *
+ * \param[in] fw_store The subject fw_store
+ * \param[in] image_info Information about the accepted image
+ *
+ * \return True if all necessary images have been accepted
+ */
+bool fw_store_notify_accepted(struct fw_store *fw_store, const struct image_info *image_info);
+
+/**
+ * \brief Check if image is accepted
+ *
+ * \param[in] fw_store The subject fw_store
+ * \param[in] image_info Information about the image
+ *
+ * \return True if image has been accepted
+ */
+bool fw_store_is_accepted(const struct fw_store *fw_store, const struct image_info *image_info);
+
+/**
+ * \brief Check if the booted firmware is being trialed
+ *
+ * \param[in] fw_store The subject fw_store
+ *
+ * \return True if trialed
+ */
+bool fw_store_is_trial(const struct fw_store *fw_store);
+
+/**
+ * \brief Commit to the complete update
+ *
+ * \param[in] fw_store The subject fw_store
+ *
+ * \return FWU status code
+ */
+int fw_store_commit_to_update(struct fw_store *fw_store);
+
+/**
+ * \brief Revert back to the previous good version (if possible)
+ *
+ * \param[in] fw_store The subject fw_store
+ *
+ * \return FWU status code
+ */
+int fw_store_revert_to_previous(struct fw_store *fw_store);
+
+/**
+ * \brief Export fw_store specific objects
+ *
+ * Provides a way of exporting objects from a concrete fw_store e.g.
+ * for coordinating with a Nwd client. A concrete fw_store may export
+ * [0..*] types of object.
+ *
+ * \param[in] fw_store The subject fw_store
+ * \param[in] uuid Identifies the object
+ * \param[out] data Pointer to data to the exported object
+ * \param[out] data_len Length of the exported object
+ * \param[out] status Status of the export operation
+ *
+ * \return True if UUID identifies an object held by the fw_store
+ */
+bool fw_store_export(struct fw_store *fw_store, const struct uuid_octets *uuid,
+ const uint8_t **data, size_t *data_len, int *status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FW_STORE_H */
diff --git a/components/service/fwu/inspector/direct/component.cmake b/components/service/fwu/inspector/direct/component.cmake
new file mode 100644
index 000000000..5faf786d3
--- /dev/null
+++ b/components/service/fwu/inspector/direct/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/direct_fw_inspector.c"
+ )
diff --git a/components/service/fwu/inspector/direct/direct_fw_inspector.c b/components/service/fwu/inspector/direct/direct_fw_inspector.c
new file mode 100644
index 000000000..503cf458a
--- /dev/null
+++ b/components/service/fwu/inspector/direct/direct_fw_inspector.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "direct_fw_inspector.h"
+
+#include "media/volume/index/volume_index.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/agent/fw_directory.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+#include "service/fwu/installer/installer.h"
+#include "service/fwu/installer/installer_index.h"
+#include "trace.h"
+
+int direct_fw_inspector_inspect(struct fw_directory *fw_dir, unsigned int boot_index)
+{
+ int status = FWU_STATUS_SUCCESS;
+
+ /* The set of registered installers determines which fw components are
+ * updatable as individual units. Each installer is able to provide
+ * a view of the set of images [0..n] that it is capable of updating using
+ * its enumerate method. This view is based on the state of the firmware
+ * at the most recent boot. The set of updatable images may change after
+ * an update because:
+ * a) The set of images within the boot volume has changed
+ * b) The set of supported installers has changed
+ *
+ * By iterating over all registered installers, a complete and fresh view
+ * of updatable images is obtained.
+ */
+ unsigned int index = 0;
+
+ do {
+ struct installer *installer = installer_index_get(index);
+
+ if (!installer)
+ break;
+
+ /* To enable an installer to inspect the firmware volume that
+ * was booted from, determined the correct volume_id based on the
+ * most recent boot_index.
+ */
+ unsigned int volume_id =
+ banked_volume_id(installer->location_id, banked_usage_id(boot_index));
+
+ /* Delegate volume inspection to the installer that will have
+ * the necessary package format knowledge to extract information
+ * about images that it is capable of updating. An installer
+ * will add 0..* image entries to the fw_directory.
+ */
+ status = installer_enumerate(installer, volume_id, fw_dir);
+
+ if (status != FWU_STATUS_SUCCESS) {
+ EMSG("Failed to enumerate contents of volume %d", volume_id);
+ break;
+ }
+
+ ++index;
+
+ } while (1);
+
+ return status;
+}
diff --git a/components/service/fwu/inspector/direct/direct_fw_inspector.h b/components/service/fwu/inspector/direct/direct_fw_inspector.h
new file mode 100644
index 000000000..0fa515fb9
--- /dev/null
+++ b/components/service/fwu/inspector/direct/direct_fw_inspector.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DIRECT_FW_INSPECTOR_H
+#define DIRECT_FW_INSPECTOR_H
+
+#include "service/fwu/inspector/fw_inspector.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief direct_fw_inspector inspect method
+ *
+ * The concrete inspect method for the direct_fw_inspector. The direct_fw_inspector
+ * is a fw_inspector that can be used when direct access to firmware storage volumes
+ * is possible e.g. when fw is loaded from Swd flash. The direct_fw_inspector delegates
+ * the enumeration of updatable images to the set of installers that were registered
+ * with the installer_index as part of the platform configuration.
+ *
+ * \param[in] fw_dir The firmware directory to refresh
+ * \param[in] boot_index The boot_index reported by the bootloader
+ *
+ * \return FWU status
+ */
+int direct_fw_inspector_inspect(struct fw_directory *fw_dir, unsigned int boot_index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DIRECT_FW_INSPECTOR_H */
diff --git a/components/service/fwu/inspector/fw_inspector.h b/components/service/fwu/inspector/fw_inspector.h
new file mode 100644
index 000000000..80481309e
--- /dev/null
+++ b/components/service/fwu/inspector/fw_inspector.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FW_INSPECTOR_H
+#define FW_INSPECTOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct fw_directory;
+
+/**
+ * \brief fw_inspector public interface definition
+ *
+ * A firmware inspector is responsible for retrieving information about the
+ * firmware associated with a fw store and refreshing the contents of the
+ * presented firmware directory. The information will reflect the state of
+ * the firmware at the most recent boot. The method used for discovering information
+ * may well vary between device classes and firmware store realizations. To
+ * give the necessary flexibility, the fw_inspector 'inspect' function may be
+ * realized by alternative implementations. To give the flexibility to
+ * combine multiple inspection strategies into a single build (for test or
+ * run-time configuration), the inspect method is called via a function pointer.
+ *
+ * \param[in] fw_dir The firmware directory to refresh
+ * \param[in] boot_index The boot_index reported by the bootloader
+ *
+ * \return FWU status
+ */
+typedef int (*fw_inspector_inspect)(struct fw_directory *fw_dir, unsigned int boot_index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FW_INSPECTOR_H */
diff --git a/components/service/fwu/inspector/mock/component.cmake b/components/service/fwu/inspector/mock/component.cmake
new file mode 100644
index 000000000..fce467db2
--- /dev/null
+++ b/components/service/fwu/inspector/mock/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/mock_fw_inspector.c"
+ )
diff --git a/components/service/fwu/inspector/mock/mock_fw_inspector.c b/components/service/fwu/inspector/mock/mock_fw_inspector.c
new file mode 100644
index 000000000..0ec12dbb9
--- /dev/null
+++ b/components/service/fwu/inspector/mock/mock_fw_inspector.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "mock_fw_inspector.h"
+
+#include "common/uuid/uuid.h"
+#include "service/fwu/agent/fw_directory.h"
+
+int mock_fw_inspector_inspect(struct fw_directory *fw_dir, unsigned int boot_index)
+{
+ (void)boot_index;
+
+ /* A mock fw inspector that populates the fw_directory with fixed entries.
+ * Intended for test purposes.
+ */
+
+ /* Add some mock image entries to represent updatable units. */
+ struct image_info image_info = { 0 };
+
+ /* Image 1 */
+ uuid_guid_octets_from_canonical(&image_info.img_type_uuid, MOCK_IMG_TYPE_UUID_1);
+ image_info.max_size = 100;
+ image_info.lowest_accepted_version = 1;
+ image_info.active_version = 2;
+ image_info.permissions = 1;
+ image_info.install_type = INSTALL_TYPE_WHOLE_VOLUME;
+
+ fw_directory_add_image_info(fw_dir, &image_info);
+
+ /* Image 2 */
+ uuid_guid_octets_from_canonical(&image_info.img_type_uuid, MOCK_IMG_TYPE_UUID_2);
+ image_info.max_size = 100;
+ image_info.lowest_accepted_version = 1;
+ image_info.active_version = 2;
+ image_info.permissions = 1;
+ image_info.install_type = INSTALL_TYPE_SUB_VOLUME;
+
+ fw_directory_add_image_info(fw_dir, &image_info);
+
+ /* Image 3 */
+ uuid_guid_octets_from_canonical(&image_info.img_type_uuid, MOCK_IMG_TYPE_UUID_3);
+ image_info.max_size = 100;
+ image_info.lowest_accepted_version = 1;
+ image_info.active_version = 2;
+ image_info.permissions = 1;
+ image_info.install_type = INSTALL_TYPE_SUB_VOLUME;
+
+ fw_directory_add_image_info(fw_dir, &image_info);
+
+ /* Image 4 */
+ uuid_guid_octets_from_canonical(&image_info.img_type_uuid, MOCK_IMG_TYPE_UUID_4);
+ image_info.max_size = 200;
+ image_info.lowest_accepted_version = 1;
+ image_info.active_version = 2;
+ image_info.permissions = 1;
+ image_info.install_type = INSTALL_TYPE_SUB_VOLUME;
+
+ fw_directory_add_image_info(fw_dir, &image_info);
+
+ return 0;
+}
diff --git a/components/service/fwu/inspector/mock/mock_fw_inspector.h b/components/service/fwu/inspector/mock/mock_fw_inspector.h
new file mode 100644
index 000000000..b31ef4231
--- /dev/null
+++ b/components/service/fwu/inspector/mock/mock_fw_inspector.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef MOCK_FW_INSPECTOR_H
+#define MOCK_FW_INSPECTOR_H
+
+#include "service/fwu/inspector/fw_inspector.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Mock image type UUIDs
+ */
+#define MOCK_IMG_TYPE_UUID_1 "7744b3ab-2672-4a36-b619-b9a3608c9973"
+#define MOCK_IMG_TYPE_UUID_2 "52b3b093-08c4-427e-8cfe-a4c3b804ed88"
+#define MOCK_IMG_TYPE_UUID_3 "14345e20-a0b6-46dd-8699-e89512596205"
+#define MOCK_IMG_TYPE_UUID_4 "420f26dc-0a91-436f-8420-f4372b88ae16"
+
+/**
+ * \brief mock_fw_inspector inspect method
+ *
+ * The concrete inspect method for the mock_fw_inspector. The mock_fw_inspector
+ * is a fw_inspector that populates the fw_directory with a fixed set of mock
+ * entries. Used for test only.
+ *
+ * \param[in] fw_dir The firmware directory to refresh
+ * \param[in] boot_index The boot_index reported by the bootloader
+ *
+ * \return FWU status
+ */
+int mock_fw_inspector_inspect(struct fw_directory *fw_dir, unsigned int boot_index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MOCK_FW_INSPECTOR_H */
diff --git a/components/service/fwu/installer/component.cmake b/components/service/fwu/installer/component.cmake
new file mode 100644
index 000000000..5f124f1c0
--- /dev/null
+++ b/components/service/fwu/installer/component.cmake
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/installer.c"
+ "${CMAKE_CURRENT_LIST_DIR}/installer_index.c"
+ )
+
+# Configurable build parameters
+# TS_CFG_FWU_MAX_INSTALLERS Maximum number of installers allowed
+# TS_CFG_FWU_MAX_LOCATIONS Maximum number of updatable locations
+if(DEFINED TS_CFG_FWU_MAX_INSTALLERS)
+ target_compile_definitions(${TGT} PRIVATE
+ INSTALLER_INDEX_LIMIT=${TS_CFG_FWU_MAX_INSTALLERS})
+endif()
+
+if(DEFINED TS_CFG_FWU_MAX_LOCATIONS)
+ target_compile_definitions(${TGT} PRIVATE
+ INSTALLER_INDEX_LOCATION_ID_LIMIT=${TS_CFG_FWU_MAX_LOCATIONS})
+endif()
diff --git a/components/service/fwu/installer/copy/component.cmake b/components/service/fwu/installer/copy/component.cmake
new file mode 100644
index 000000000..67032090d
--- /dev/null
+++ b/components/service/fwu/installer/copy/component.cmake
@@ -0,0 +1,16 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/copy_installer.c"
+ )
+
+target_compile_definitions(${TGT} PRIVATE
+ COPY_INSTALLER_AVAILABLE) \ No newline at end of file
diff --git a/components/service/fwu/installer/copy/copy_installer.c b/components/service/fwu/installer/copy/copy_installer.c
new file mode 100644
index 000000000..84543a346
--- /dev/null
+++ b/components/service/fwu/installer/copy/copy_installer.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "copy_installer.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "media/volume/index/volume_index.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "util.h"
+
+#define COPY_CHUNK_SIZE (4096)
+
+static int close_volumes_on_error(struct copy_installer *subject)
+{
+ volume_close(subject->source_volume);
+ volume_close(subject->destination_volume);
+
+ return FWU_STATUS_UNKNOWN;
+}
+
+static int copy_volume_contents(struct copy_installer *subject, size_t target_copy_len)
+{
+ int status = FWU_STATUS_SUCCESS;
+ size_t copy_len = 0;
+ uint8_t *copy_buf = malloc(COPY_CHUNK_SIZE);
+
+ if (!copy_buf)
+ return FWU_STATUS_UNKNOWN;
+
+ while (copy_len < target_copy_len) {
+ size_t actual_read_len = 0;
+ size_t actual_write_len = 0;
+ size_t remaining_len = target_copy_len - copy_len;
+ size_t requested_read_len = (remaining_len < COPY_CHUNK_SIZE) ? remaining_len :
+ COPY_CHUNK_SIZE;
+
+ status = volume_read(subject->source_volume, (uintptr_t)copy_buf,
+ requested_read_len, &actual_read_len);
+
+ if (status)
+ break;
+
+ status = volume_write(subject->destination_volume, (const uintptr_t)copy_buf,
+ actual_read_len, &actual_write_len);
+
+ if (status)
+ break;
+
+ if (actual_read_len != actual_write_len) {
+ status = FWU_STATUS_UNKNOWN;
+ break;
+ }
+
+ copy_len += actual_read_len;
+ }
+
+ free(copy_buf);
+
+ return status;
+}
+
+static int copy_installer_begin(void *context, unsigned int current_volume_id,
+ unsigned int update_volume_id)
+{
+ struct copy_installer *subject = (struct copy_installer *)context;
+
+ int status = volume_index_find(update_volume_id, &subject->destination_volume);
+
+ if (status == 0) {
+ status = volume_index_find(current_volume_id, &subject->source_volume);
+ }
+
+ if (status != 0) {
+ subject->destination_volume = NULL;
+ subject->source_volume = NULL;
+ }
+
+ return status;
+}
+
+static int copy_installer_finalize(void *context)
+{
+ struct copy_installer *subject = (struct copy_installer *)context;
+
+ assert(subject->source_volume);
+ assert(subject->destination_volume);
+
+ /* Open the source and destination volumes */
+ int source_status = volume_open(subject->source_volume);
+
+ if (source_status)
+ return source_status;
+
+ int destination_status = volume_open(subject->destination_volume);
+
+ if (destination_status) {
+ volume_close(subject->source_volume);
+ return destination_status;
+ }
+
+ /* Prepare the destination volume for writes */
+ destination_status = volume_erase(subject->destination_volume);
+
+ if (destination_status)
+ return close_volumes_on_error(subject);
+
+ /* Determine how much to copy */
+ size_t source_size = 0;
+ size_t destination_size = 0;
+
+ source_status = volume_size(subject->source_volume, &source_size);
+
+ if (source_status)
+ return close_volumes_on_error(subject);
+
+ destination_status = volume_size(subject->source_volume, &destination_size);
+
+ if (destination_status)
+ return close_volumes_on_error(subject);
+
+ /* Perform the copy */
+ int copy_status = copy_volume_contents(subject, MIN(source_size, destination_size));
+
+ /* All done */
+ source_status = volume_close(subject->source_volume);
+ destination_status = volume_close(subject->destination_volume);
+
+ return (copy_status) ? copy_status :
+ (destination_status) ? destination_status :
+ (source_status) ? source_status :
+ FWU_STATUS_SUCCESS;
+}
+
+static void copy_installer_abort(void *context)
+{
+ struct copy_installer *subject = (struct copy_installer *)context;
+
+ subject->source_volume = NULL;
+ subject->destination_volume = NULL;
+}
+
+static int copy_installer_open(void *context, const struct image_info *image_info)
+{
+ (void)context;
+ (void)image_info;
+
+ return FWU_STATUS_DENIED;
+}
+
+static int copy_installer_commit(void *context)
+{
+ (void)context;
+
+ return FWU_STATUS_DENIED;
+}
+
+static int copy_installer_write(void *context, const uint8_t *data, size_t data_len)
+{
+ (void)context;
+ (void)data;
+ (void)data_len;
+
+ return FWU_STATUS_DENIED;
+}
+
+static int copy_installer_enumerate(void *context, uint32_t volume_id,
+ struct fw_directory *fw_directory)
+{
+ (void)volume_id;
+ (void)fw_directory;
+
+ /* A copy_installer can never be used to install externally provided images
+ * don't advertise any images via the fw_directory. Just quietly return success.
+ */
+ return FWU_STATUS_SUCCESS;
+}
+
+void copy_installer_init(struct copy_installer *subject, const struct uuid_octets *location_uuid,
+ uint32_t location_id)
+{
+ /* Define concrete installer interface */
+ static const struct installer_interface interface = {
+ copy_installer_begin, copy_installer_finalize, copy_installer_abort,
+ copy_installer_open, copy_installer_commit, copy_installer_write,
+ copy_installer_enumerate
+ };
+
+ /* Initialize base installer - a copy_installer is a type of
+ * installer that always updates a whole volume by copying
+ * from another.
+ */
+ installer_init(&subject->base_installer, INSTALL_TYPE_WHOLE_VOLUME_COPY, location_id,
+ location_uuid, subject, &interface);
+
+ /* Initialize copy_installer specifics */
+ subject->source_volume = NULL;
+ subject->destination_volume = NULL;
+}
+
+void copy_installer_deinit(struct copy_installer *subject)
+{
+ (void)subject;
+}
diff --git a/components/service/fwu/installer/copy/copy_installer.h b/components/service/fwu/installer/copy/copy_installer.h
new file mode 100644
index 000000000..3aaf6a357
--- /dev/null
+++ b/components/service/fwu/installer/copy/copy_installer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FWU_COPY_INSTALLER_H
+#define FWU_COPY_INSTALLER_H
+
+#include <stdint.h>
+
+#include "media/volume/volume.h"
+#include "service/fwu/installer/installer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief copy_installer structure definition
+ *
+ * A copy_installer is an installer that copies previously installed images
+ * from a source volume into a destination volume. A copy_installer does not
+ * consume externally provided installation data. A copy_installer may be
+ * used in situations where an update has resulted in no change to the
+ * firmware for a subsystem (location) but it is necessary to copy image
+ * data to the update bank. The copy_installer has no knowledge of the
+ * actual size of image data that needs to copied so the entire source
+ * volume is copied to the destination. This will potentially be wasteful
+ * in that unnecessary data may be copied.
+ */
+struct copy_installer {
+ struct installer base_installer;
+ struct volume *destination_volume;
+ struct volume *source_volume;
+};
+
+/**
+ * \brief Initialize a copy_installer
+ *
+ * \param[in] subject The subject copy_installer
+ * \param[in] location_uuid The associated location UUID
+ * \param[in] location_id Identifies where to install qualifying images
+ */
+void copy_installer_init(struct copy_installer *subject, const struct uuid_octets *location_uuid,
+ uint32_t location_id);
+
+/**
+ * \brief De-initialize a copy_installer
+ *
+ * \param[in] subject The subject copy_installer
+ */
+void copy_installer_deinit(struct copy_installer *subject);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FWU_COPY_INSTALLER_H */
diff --git a/components/service/fwu/installer/copy/test/component.cmake b/components/service/fwu/installer/copy/test/component.cmake
new file mode 100644
index 000000000..61a12ad8a
--- /dev/null
+++ b/components/service/fwu/installer/copy/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/copy_installer_tests.cpp"
+ )
diff --git a/components/service/fwu/installer/copy/test/copy_installer_tests.cpp b/components/service/fwu/installer/copy/test/copy_installer_tests.cpp
new file mode 100644
index 000000000..ac7209262
--- /dev/null
+++ b/components/service/fwu/installer/copy/test/copy_installer_tests.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <cstdlib>
+#include <cstring>
+
+#include "common/uuid/uuid.h"
+#include "media/disk/guid.h"
+#include "media/volume/block_volume/block_volume.h"
+#include "media/volume/index/volume_index.h"
+#include "media/volume/volume.h"
+#include "service/block_storage/config/ref/ref_partition_configurator.h"
+#include "service/block_storage/factory/ref_ram_gpt/block_store_factory.h"
+#include "service/fwu/agent/fw_directory.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+#include "service/fwu/installer/copy/copy_installer.h"
+#include "service/fwu/installer/installer_index.h"
+#include "service/fwu/installer/raw/raw_installer.h"
+
+TEST_GROUP(FwuCopyInstallerTests)
+{
+ void setup()
+ {
+ int result;
+ struct uuid_octets partition_guid;
+
+ m_image = NULL;
+
+ installer_index_init();
+ volume_index_init();
+
+ /* Use the reference disk configuration and use partition 1 & 2 as
+ * storage for A and B firmware banks.
+ */
+ m_block_store = ref_ram_gpt_block_store_factory_create();
+
+ /* Construct fw volume A */
+ uuid_guid_octets_from_canonical(&partition_guid, REF_PARTITION_1_GUID);
+
+ result = block_volume_init(&m_block_volume_a, m_block_store, &partition_guid,
+ &m_fw_volume_a);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_fw_volume_a);
+
+ /* Construct fw volume B */
+ uuid_guid_octets_from_canonical(&partition_guid, REF_PARTITION_2_GUID);
+
+ result = block_volume_init(&m_block_volume_b, m_block_store, &partition_guid,
+ &m_fw_volume_b);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_fw_volume_b);
+
+ /* Prepare an image_info structure to describe the image to
+ * install into one of volumes.
+ */
+ uuid_guid_octets_from_canonical(&m_image_info.img_type_uuid,
+ "1c22ca2c-9732-49e6-ba3b-eed40e27fda3");
+
+ m_image_info.max_size =
+ (REF_PARTITION_1_ENDING_LBA - REF_PARTITION_1_STARTING_LBA + 1) *
+ REF_PARTITION_BLOCK_SIZE;
+ m_image_info.lowest_accepted_version = 1;
+ m_image_info.active_version = 1;
+ m_image_info.permissions = 0;
+ m_image_info.image_index = 0;
+ m_image_info.location_id = FW_STORE_LOCATION_ID;
+ m_image_info.install_type = INSTALL_TYPE_WHOLE_VOLUME;
+
+ /* Mimic a platform configuration where storage volumes are assigned
+ * location and usage IDs. These usage IDs correspond to an A/B banked
+ * firmware store.
+ */
+ volume_index_add(banked_volume_id(FW_STORE_LOCATION_ID, BANKED_USAGE_ID_FW_BANK_A),
+ m_fw_volume_a);
+ volume_index_add(banked_volume_id(FW_STORE_LOCATION_ID, BANKED_USAGE_ID_FW_BANK_B),
+ m_fw_volume_b);
+
+ /* A platform configuration will also determine which installers are
+ * assigned to which locations. For these tests, there is a raw_installer
+ * to install the initial image and a copy_installer to install a copy
+ * into the other bank.
+ */
+ raw_installer_init(&m_raw_installer, &m_image_info.img_type_uuid,
+ FW_STORE_LOCATION_ID);
+ installer_index_register(&m_raw_installer.base_installer);
+
+ copy_installer_init(&m_copy_installer, &m_image_info.img_type_uuid,
+ FW_STORE_LOCATION_ID);
+ installer_index_register(&m_copy_installer.base_installer);
+ }
+
+ void teardown()
+ {
+ delete[] m_image;
+
+ raw_installer_deinit(&m_raw_installer);
+ copy_installer_deinit(&m_copy_installer);
+
+ installer_index_clear();
+ volume_index_clear();
+
+ block_volume_deinit(&m_block_volume_a);
+ block_volume_deinit(&m_block_volume_b);
+ ref_ram_gpt_block_store_factory_destroy(m_block_store);
+ }
+
+ void create_image(size_t len)
+ {
+ m_image = new uint8_t[len];
+ m_image_len = len;
+
+ for (size_t i = 0; i < len; i++)
+ m_image[i] = (uint8_t)rand();
+ }
+
+ void install_initial_image(size_t len)
+ {
+ create_image(len);
+
+ /* Expect to find a suitable installer for the given image_info */
+ struct installer *installer =
+ installer_index_find(m_image_info.install_type, m_image_info.location_id);
+ CHECK_TRUE(installer);
+ UNSIGNED_LONGS_EQUAL(FW_STORE_LOCATION_ID, installer->location_id);
+
+ /* Begin installation transaction - installing into volume A */
+ int status = installer_begin(
+ installer,
+ banked_volume_id(FW_STORE_LOCATION_ID,
+ BANKED_USAGE_ID_FW_BANK_B), /* Current volume */
+ banked_volume_id(FW_STORE_LOCATION_ID,
+ BANKED_USAGE_ID_FW_BANK_A)); /* Update volume */
+ LONGS_EQUAL(0, status);
+
+ status = installer_open(installer, &m_image_info);
+ LONGS_EQUAL(0, status);
+
+ status = installer_write(installer, m_image, m_image_len);
+ LONGS_EQUAL(0, status);
+
+ status = installer_commit(installer);
+ LONGS_EQUAL(0, status);
+
+ status = installer_finalize(installer);
+ LONGS_EQUAL(0, status);
+
+ check_update_installed(m_fw_volume_a);
+ }
+
+ void check_update_installed(struct volume * volume)
+ {
+ int status = 0;
+ size_t total_read = 0;
+
+ status = volume_open(volume);
+ LONGS_EQUAL(0, status);
+
+ while (total_read < m_image_len) {
+ uint8_t read_buf[1000];
+ size_t len_read = 0;
+ size_t bytes_remaining = m_image_len - total_read;
+ size_t req_len = (bytes_remaining > sizeof(read_buf)) ? sizeof(read_buf) :
+ bytes_remaining;
+
+ memset(read_buf, 0, sizeof(read_buf));
+
+ status = volume_read(volume, (uintptr_t)read_buf, req_len, &len_read);
+ LONGS_EQUAL(0, status);
+ UNSIGNED_LONGS_EQUAL(req_len, len_read);
+
+ MEMCMP_EQUAL(&m_image[total_read], read_buf, len_read);
+
+ total_read += len_read;
+ }
+
+ status = volume_close(volume);
+ LONGS_EQUAL(0, status);
+ }
+
+ static const unsigned int FW_STORE_LOCATION_ID = 0x100;
+
+ struct block_store *m_block_store;
+ struct block_volume m_block_volume_a;
+ struct block_volume m_block_volume_b;
+ struct volume *m_fw_volume_a;
+ struct volume *m_fw_volume_b;
+ struct raw_installer m_raw_installer;
+ struct copy_installer m_copy_installer;
+ struct image_info m_image_info;
+ uint8_t *m_image;
+ size_t m_image_len;
+};
+
+TEST(FwuCopyInstallerTests, installAndCopy)
+{
+ /* Install an arbitrary size image into bank A */
+ install_initial_image(13011);
+
+ /* Expect to find a suitable copy installer */
+ struct installer *installer =
+ installer_index_find(INSTALL_TYPE_WHOLE_VOLUME_COPY, FW_STORE_LOCATION_ID);
+ CHECK_TRUE(installer);
+ UNSIGNED_LONGS_EQUAL(FW_STORE_LOCATION_ID, installer->location_id);
+
+ /* Begin installation transaction - installing into volume B */
+ int status =
+ installer_begin(installer,
+ banked_volume_id(FW_STORE_LOCATION_ID,
+ BANKED_USAGE_ID_FW_BANK_A), /* Current volume */
+ banked_volume_id(FW_STORE_LOCATION_ID,
+ BANKED_USAGE_ID_FW_BANK_B)); /* Update volume */
+ LONGS_EQUAL(0, status);
+
+ /* Finalize the installation - the copy should happen here */
+ status = installer_finalize(installer);
+ LONGS_EQUAL(0, status);
+
+ /* Expect volume B to contain a copy of what's in volume A */
+ check_update_installed(m_fw_volume_b);
+}
diff --git a/components/service/fwu/installer/factory/default/component.cmake b/components/service/fwu/installer/factory/default/component.cmake
new file mode 100644
index 000000000..7cb663459
--- /dev/null
+++ b/components/service/fwu/installer/factory/default/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/installer_factory.c"
+ )
diff --git a/components/service/fwu/installer/factory/default/installer_factory.c b/components/service/fwu/installer/factory/default/installer_factory.c
new file mode 100644
index 000000000..506f9632a
--- /dev/null
+++ b/components/service/fwu/installer/factory/default/installer_factory.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "service/fwu/installer/factory/installer_factory.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/uuid/uuid.h"
+#include "service/fwu/installer/copy/copy_installer.h"
+#include "service/fwu/installer/factory/locations.h"
+#include "service/fwu/installer/installer.h"
+#include "service/fwu/installer/raw/raw_installer.h"
+
+/**
+ * An installer factory for constructing installers for a platform
+ * that conforms to the following constraints:
+ *
+ * 1. AP firmware is contained within a FIP that resides within a separate
+ * storage volume (* n banks). A volume will normally map to a flash partition.
+ * 2. SCP firmware, if present, is always updated as a single unit and resides in
+ * a separate storage volume.
+ * 3. RSS firmware, if present, is always updated as a single unit and resides in
+ * a separate storage volume.
+ */
+
+static bool check_supported_locations(const char *const supported_uuids[],
+ const struct uuid_octets *location_uuid)
+{
+ bool is_supported = false;
+ unsigned int i = 0;
+
+ while (supported_uuids[i]) {
+ struct uuid_octets comparison_uuid;
+
+ uuid_guid_octets_from_canonical(&comparison_uuid, supported_uuids[i]);
+
+ if (uuid_is_equal(comparison_uuid.octets, location_uuid->octets)) {
+ is_supported = true;
+ break;
+ }
+
+ ++i;
+ }
+
+ return is_supported;
+}
+
+struct installer *installer_factory_create_installer(enum install_type installation_type,
+ unsigned int location_id,
+ const struct uuid_octets *location_uuid)
+{
+ assert(location_uuid);
+
+ struct installer *product = NULL;
+
+ if (installation_type == INSTALL_TYPE_WHOLE_VOLUME) {
+#ifdef RAW_INSTALLER_AVAILABLE
+ static const char *const raw_installer_compatibility[] = {
+ LOCATION_UUID_AP_FW, LOCATION_UUID_SCP_FW, LOCATION_UUID_RSS_FW, NULL
+ };
+
+ if (check_supported_locations(raw_installer_compatibility, location_uuid)) {
+ struct raw_installer *raw_installer =
+ (struct raw_installer *)malloc(sizeof(struct raw_installer));
+
+ if (raw_installer) {
+ raw_installer_init(raw_installer, location_uuid, location_id);
+ product = &raw_installer->base_installer;
+ }
+ }
+#endif
+
+ } else if (installation_type == INSTALL_TYPE_WHOLE_VOLUME_COPY) {
+#ifdef COPY_INSTALLER_AVAILABLE
+ static const char *const copy_installer_compatibility[] = {
+ LOCATION_UUID_AP_FW, LOCATION_UUID_SCP_FW, LOCATION_UUID_RSS_FW, NULL
+ };
+
+ if (check_supported_locations(copy_installer_compatibility, location_uuid)) {
+ struct copy_installer *copy_installer =
+ (struct copy_installer *)malloc(sizeof(struct copy_installer));
+
+ if (copy_installer) {
+ copy_installer_init(copy_installer, location_uuid, location_id);
+ product = &copy_installer->base_installer;
+ }
+ }
+#endif
+ }
+
+ return product;
+}
+
+void installer_factory_destroy_installer(struct installer *installer)
+{
+ if (installer)
+ free(installer->context);
+}
diff --git a/components/service/fwu/installer/factory/default/test/component.cmake b/components/service/fwu/installer/factory/default/test/component.cmake
new file mode 100644
index 000000000..b9da3aa5b
--- /dev/null
+++ b/components/service/fwu/installer/factory/default/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/default_installer_factory_tests.cpp"
+ )
diff --git a/components/service/fwu/installer/factory/default/test/default_installer_factory_tests.cpp b/components/service/fwu/installer/factory/default/test/default_installer_factory_tests.cpp
new file mode 100644
index 000000000..213a26523
--- /dev/null
+++ b/components/service/fwu/installer/factory/default/test/default_installer_factory_tests.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+
+#include "common/uuid/uuid.h"
+#include "media/disk/guid.h"
+#include "service/fwu/installer/factory/installer_factory.h"
+#include "service/fwu/installer/factory/locations.h"
+#include "service/fwu/installer/installer_index.h"
+
+TEST_GROUP(FwuDefaultInstallerFactoryTests){ void setup(){ installer_index_init();
+}
+
+void teardown()
+{
+ unsigned int i = 0;
+
+ do {
+ struct installer *installer = installer_index_get(i);
+
+ if (!installer)
+ break;
+
+ installer_factory_destroy_installer(installer);
+ ++i;
+
+ } while (1);
+
+ installer_index_clear();
+}
+}
+;
+
+TEST(FwuDefaultInstallerFactoryTests, configureInstallersFlow)
+{
+ struct uuid_octets ap_fw_uuid;
+ struct uuid_octets scp_fw_uuid;
+ struct uuid_octets rss_fw_uuid;
+
+ /* Check configuration operations that will be performed when
+ * constructing a set of installers for a platform. The platform
+ * consists of multiple firmware locations. This sequence
+ * represents the configuration steps performed when iterating
+ * over a GPT to identify updatable partitions.
+ */
+
+ /* Configure installers for updating AP firmware */
+ uuid_guid_octets_from_canonical(&ap_fw_uuid, LOCATION_UUID_AP_FW);
+
+ /* Expect no installer to initially be registered */
+ CHECK_FALSE(installer_index_find_by_location_uuid(&ap_fw_uuid));
+
+ /* Configure for whole volume and copy installation */
+ struct installer *installer =
+ installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME, 0, &ap_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&ap_fw_uuid));
+
+ installer =
+ installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME_COPY, 0, &ap_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&ap_fw_uuid));
+
+ /* Configure installers for updating SCP firmware */
+ uuid_guid_octets_from_canonical(&scp_fw_uuid, LOCATION_UUID_SCP_FW);
+
+ /* Expect no installer to initially be registered */
+ CHECK_FALSE(installer_index_find_by_location_uuid(&scp_fw_uuid));
+
+ /* Configure for whole volume and copy installation */
+ installer = installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME, 0, &scp_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&scp_fw_uuid));
+
+ installer =
+ installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME_COPY, 0, &scp_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&scp_fw_uuid));
+
+ /* Configure installers for updating RSS firmware */
+ uuid_guid_octets_from_canonical(&rss_fw_uuid, LOCATION_UUID_RSS_FW);
+
+ /* Expect no installer to initially be registered */
+ CHECK_FALSE(installer_index_find_by_location_uuid(&rss_fw_uuid));
+
+ /* Configure for whole volume and copy installation */
+ installer = installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME, 0, &rss_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&rss_fw_uuid));
+
+ installer =
+ installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME_COPY, 0, &rss_fw_uuid);
+ CHECK_TRUE(installer);
+
+ installer_index_register(installer);
+ CHECK_TRUE(installer_index_find_by_location_uuid(&rss_fw_uuid));
+
+ /* Now try and construct an installer for an unsupported partition type. */
+ struct uuid_octets unsupported_location_uuid;
+
+ uuid_guid_octets_from_canonical(&unsupported_location_uuid,
+ DISK_GUID_PARTITION_TYPE_FWU_METADATA);
+
+ installer = installer_factory_create_installer(INSTALL_TYPE_WHOLE_VOLUME, 0,
+ &unsupported_location_uuid);
+ CHECK_FALSE(installer);
+
+ CHECK_FALSE(installer_index_find_by_location_uuid(&unsupported_location_uuid));
+}
diff --git a/components/service/fwu/installer/factory/installer_factory.h b/components/service/fwu/installer/factory/installer_factory.h
new file mode 100644
index 000000000..b903be90a
--- /dev/null
+++ b/components/service/fwu/installer/factory/installer_factory.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INSTALLER_FACTORY_H
+#define INSTALLER_FACTORY_H
+
+#include "common/uuid/uuid.h"
+#include "service/fwu/agent/install_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct installer;
+
+/**
+ * \brief An interface for constructing image installers
+ *
+ * The FWU update service can be used to install a diverse range of firmware images. To
+ * allow for platform specific installers that handle different image formats and installation
+ * methods, a common interface is used for constructing concrete installers. The implementation
+ * of the installer_factory determines the set of concrete installers that are available
+ * in a deployment. It is envisaged that alternative factory implementations will be needed
+ * to cater for different classes of product with different installation requirements. A
+ * constructed installer should be destroyed using the installer_factory_destroy_installer
+ * method when the installer is no longer needed.
+ *
+ * \param[in] installation_type The type of installation required
+ * \param[in] location_id The short location_id that corresponds to the location_uuid
+ * \param[in] location_uuid UUID to identify the location into which images will be installed
+ *
+ * \return The constructed installer or NULL if no suitable installer can be constructed.
+ */
+struct installer *installer_factory_create_installer(enum install_type installation_type,
+ unsigned int location_id,
+ const struct uuid_octets *location_uuid);
+
+/**
+ * \brief Destroy an installer
+ *
+ * \param[in] installer Installer to destroy
+ */
+void installer_factory_destroy_installer(struct installer *installer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INSTALLER_FACTORY_H */
diff --git a/components/service/fwu/installer/factory/locations.h b/components/service/fwu/installer/factory/locations.h
new file mode 100644
index 000000000..4df784364
--- /dev/null
+++ b/components/service/fwu/installer/factory/locations.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INSTALLER_FACTORY_LOCATIONS_H
+#define INSTALLER_FACTORY_LOCATIONS_H
+
+/**
+ * Locations represent updatable firmware subsystems. Installers target
+ * locations for image installation purposes. A location is identified
+ * by a UUID. Where firmware images are stored within GPT formatted
+ * storage, a location UUID is used as the partition type GUID. For
+ * example, the A and B partitions holding application processor
+ * firmware will both be labelled with the same partition type GUID.
+ * The following UUIDs identify locations used by concrete installer
+ * factories as a qualifier for rules that define which installers
+ * are needed to update particular locations. New location UUIDs may
+ * be freely added to this file.
+ */
+
+/* Location UUID for application processor firmware */
+#define LOCATION_UUID_AP_FW "2451cd6e-90fe-4b15-bf10-a69bce2d4486"
+
+/* Location UUID for SCP firmware */
+#define LOCATION_UUID_SCP_FW "691d5ea3-27fe-4104-badd-7539c00a9095"
+
+/* Location UUID for RSS firmware */
+#define LOCATION_UUID_RSS_FW "c948a156-58cb-4c38-b406-e60bff2223d5"
+
+#endif /* INSTALLER_FACTORY_LOCATIONS_H */
diff --git a/components/service/fwu/installer/installer.c b/components/service/fwu/installer/installer.c
new file mode 100644
index 000000000..b69a71c24
--- /dev/null
+++ b/components/service/fwu/installer/installer.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "installer.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "protocols/service/fwu/packed-c/status.h"
+
+void installer_init(struct installer *installer, enum install_type install_type,
+ uint32_t location_id, const struct uuid_octets *location_uuid, void *context,
+ const struct installer_interface *interface)
+{
+ assert(installer);
+ assert(location_uuid);
+ assert(context);
+ assert(interface);
+
+ installer->install_type = install_type;
+ installer->location_id = location_id;
+ installer->location_uuid = *location_uuid;
+ installer->context = context;
+ installer->interface = interface;
+
+ installer->install_status = FWU_STATUS_SUCCESS;
+ installer->is_active = false;
+ installer->next = NULL;
+}
+
+int installer_begin(struct installer *installer, uint32_t current_volume_id,
+ uint32_t update_volume_id)
+{
+ assert(installer);
+ assert(installer->interface);
+ assert(installer->interface->begin);
+
+ installer->install_status = FWU_STATUS_SUCCESS;
+ installer->is_active = true;
+
+ return installer->interface->begin(installer->context, current_volume_id, update_volume_id);
+}
+
+int installer_finalize(struct installer *installer)
+{
+ assert(installer);
+ assert(installer->interface);
+ assert(installer->interface->finalize);
+
+ installer->is_active = false;
+
+ return installer->interface->finalize(installer->context);
+}
+
+void installer_abort(struct installer *installer)
+{
+ assert(installer);
+ assert(installer->interface);
+ assert(installer->interface->abort);
+
+ installer->is_active = false;
+
+ installer->interface->abort(installer->context);
+}
+
+int installer_open(struct installer *installer, const struct image_info *image_info)
+{
+ assert(installer);
+ assert(installer->interface);
+ assert(installer->interface->open);
+
+ int status = installer->interface->open(installer->context, image_info);
+
+ if (status && !installer->install_status)
+ installer->install_status = status;
+
+ return status;
+}
+
+int installer_commit(struct installer *installer)
+{
+ assert(installer);
+ assert(installer->interface);
+ assert(installer->interface->commit);
+
+ int status = installer->interface->commit(installer->context);
+
+ if (status && !installer->install_status)
+ installer->install_status = status;
+
+ return status;
+}
+
+int installer_write(struct installer *installer, const uint8_t *data, size_t data_len)
+{
+ assert(installer);
+ assert(installer->interface);
+ assert(installer->interface->write);
+
+ int status = installer->interface->write(installer->context, data, data_len);
+
+ if (status && !installer->install_status)
+ installer->install_status = status;
+
+ return status;
+}
+
+int installer_enumerate(struct installer *installer, uint32_t volume_id,
+ struct fw_directory *fw_directory)
+{
+ assert(installer);
+ assert(installer->interface);
+ assert(installer->interface->enumerate);
+
+ return installer->interface->enumerate(installer->context, volume_id, fw_directory);
+}
diff --git a/components/service/fwu/installer/installer.h b/components/service/fwu/installer/installer.h
new file mode 100644
index 000000000..e8bddb070
--- /dev/null
+++ b/components/service/fwu/installer/installer.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FWU_INSTALLATION_INSTALLER_H
+#define FWU_INSTALLATION_INSTALLER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "common/uuid/uuid.h"
+#include "service/fwu/agent/install_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct image_info;
+struct fw_directory;
+
+/**
+ * \brief Image installer interface
+ *
+ * The installer_interface structure provides a common interface for
+ * any image installer. Concrete installers will implement installation
+ * strategies that match the class of image being installed (e.g. component,
+ * whole firmware).
+ */
+struct installer_interface {
+ /**
+ * \brief Begin a transaction of one or more image install operations
+ *
+ * \param[in] context The concrete installer context
+ * \param[in] current_volume_id Where the active fw was loaded from
+ * \param[out] update_volume_id Where the update should be installed
+ *
+ * \return FWU status
+ */
+ int (*begin)(void *context, uint32_t current_volume_id, uint32_t update_volume_id);
+
+ /**
+ * \brief Finalize a transaction of one or more image install operations
+ *
+ * \param[in] context The concrete installer context
+ *
+ * \return FWU status
+ */
+ int (*finalize)(void *context);
+
+ /**
+ * \brief Abort a transaction
+ *
+ * \param[in] context The concrete installer context
+ */
+ void (*abort)(void *context);
+
+ /**
+ * \brief Open a stream for writing installation data
+ *
+ * \param[in] context The concrete installer context
+ * \param[in] image_info Describes the image to install
+ *
+ * \return FWU status
+ */
+ int (*open)(void *context, const struct image_info *image_info);
+
+ /**
+ * \brief Commit installed data (called once per open)
+ *
+ * \param[in] context The concrete installer context
+ *
+ * \return FWU status
+ */
+ int (*commit)(void *context);
+
+ /**
+ * \brief Write installation data to an opened installer
+ *
+ * \param[in] context The concrete installer context
+ * \param[in] data Data to write
+ * \param[in] data_len Length of data
+ *
+ * \return FWU status
+ */
+ int (*write)(void *context, const uint8_t *data, size_t data_len);
+
+ /**
+ * \brief Enumerate the collection of images that can be handled by the installer
+ *
+ * A concrete installer will use its specialized knowledge of the associated
+ * storage volume to enumerate the set of images that can be handled by the
+ * installer.
+ *
+ * \param[in] context The concrete installer context
+ * \param[in] volume_id Identifies the target volume
+ * \param[in] fw_directory Add results to this fw_directory
+ *
+ * \return FWU status
+ */
+ int (*enumerate)(void *context, uint32_t volume_id, struct fw_directory *fw_directory);
+};
+
+/**
+ * \brief Base installer structure
+ *
+ */
+struct installer {
+ /* The installation type handled by the installer */
+ enum install_type install_type;
+
+ /* The location id is a short ID that identifies an updatable logical
+ * portion of the firmware store. The location id only needs to be
+ * unique within the device and will have been assigned dynamically
+ * during FWU configuration. The location id is used to bind a set of
+ * installers to the intended set of target volumes.
+ */
+ uint32_t location_id;
+
+ /* The location UUID is a globally unique ID that reflects the same
+ * logical scope as a location id. It is used to associate incoming
+ * update images, either directly or indirectly, to the corresponding
+ * location within the firmware store. For images contained within a
+ * disk partition, this will correspond to the partition type UUID.
+ */
+ struct uuid_octets location_uuid;
+
+ /* The opaque context for the concrete installer */
+ void *context;
+
+ /* Pointer to a concrete installer_interface */
+ const struct installer_interface *interface;
+
+ /* Error status encountered during an update transaction. During an update,
+ * an installer will be called multiple times. If one or more errors are encountered
+ * during the update transaction, the first error status is saved to allow for
+ * appropriate handling.
+ */
+ uint32_t install_status;
+
+ /**
+ * During a multi-image update, images may be delegated to different concrete
+ * installers to allow for alternative installation strategies and install destinations.
+ * Each active installer must be sequenced through a begin->finalize transaction to
+ * ensure that installation operations are completed for all images handled by an
+ * installer and by all installers used during the update.
+ */
+ bool is_active;
+ struct installer *next;
+};
+
+static inline bool installer_is_active(const struct installer *installer)
+{
+ return installer->is_active;
+}
+
+static inline uint32_t installer_status(const struct installer *installer)
+{
+ return installer->install_status;
+}
+
+void installer_init(struct installer *installer, enum install_type install_type,
+ uint32_t location_id, const struct uuid_octets *location_uuid, void *context,
+ const struct installer_interface *interface);
+
+int installer_begin(struct installer *installer, uint32_t current_volume_id,
+ uint32_t update_volume_id);
+
+int installer_finalize(struct installer *installer);
+
+void installer_abort(struct installer *installer);
+
+int installer_open(struct installer *installer, const struct image_info *image_info);
+
+int installer_commit(struct installer *installer);
+
+int installer_write(struct installer *installer, const uint8_t *data, size_t data_len);
+
+int installer_enumerate(struct installer *installer, uint32_t volume_id,
+ struct fw_directory *fw_directory);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FWU_INSTALLATION_INSTALLER_H */
diff --git a/components/service/fwu/installer/installer_index.c b/components/service/fwu/installer/installer_index.c
new file mode 100644
index 000000000..a5a62907c
--- /dev/null
+++ b/components/service/fwu/installer/installer_index.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "installer_index.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "installer.h"
+#include "trace.h"
+
+#ifndef INSTALLER_INDEX_LIMIT
+#define INSTALLER_INDEX_LIMIT (8)
+#endif
+
+#ifndef INSTALLER_INDEX_LOCATION_ID_LIMIT
+#define INSTALLER_INDEX_LOCATION_ID_LIMIT (8)
+#endif
+
+/**
+ * Singleton index of installers to use for different classes of image.
+ */
+static struct {
+ /* An index for registered installers to handle update installation
+ * for the platform. The set of registered installers will have been
+ * selected for compatibility with the class of update image handled
+ * by the installer.
+ */
+ size_t num_registered;
+ struct installer *installers[INSTALLER_INDEX_LIMIT];
+
+ /* Each installer is associated with a location via the assigned
+ * location_id. This is used as a logical identifier for the part
+ * of the device firmware that the installer handles. Multiple
+ * installers may be associated with the same location.
+ */
+ size_t num_location_ids;
+ uint32_t location_ids[INSTALLER_INDEX_LOCATION_ID_LIMIT];
+
+} installer_index;
+
+static void add_location_id(uint32_t location_id)
+{
+ /* Check if location_id already added. Because 1..* installers
+ * may be associated with the same location_id, we can ignore
+ * location_ids that have already been added.
+ */
+ for (size_t i = 0; i < installer_index.num_location_ids; i++) {
+ if (location_id == installer_index.location_ids[i])
+ return;
+ }
+
+ /* It's a new location_id so add it */
+ if (installer_index.num_location_ids < INSTALLER_INDEX_LOCATION_ID_LIMIT) {
+ installer_index.location_ids[installer_index.num_location_ids] = location_id;
+ ++installer_index.num_location_ids;
+ } else {
+ EMSG("Too many FWU locations");
+ }
+}
+
+void installer_index_init(void)
+{
+ installer_index_clear();
+}
+
+void installer_index_clear(void)
+{
+ memset(&installer_index, 0, sizeof(installer_index));
+}
+
+void installer_index_register(struct installer *installer)
+{
+ assert(installer);
+
+ if (installer_index.num_registered < INSTALLER_INDEX_LIMIT) {
+ installer_index.installers[installer_index.num_registered] = installer;
+ ++installer_index.num_registered;
+
+ add_location_id(installer->location_id);
+ } else {
+ EMSG("FWU configuration exceeds installer limit");
+ }
+}
+
+struct installer *installer_index_find(enum install_type install_type, uint32_t location_id)
+{
+ struct installer *result = NULL;
+
+ for (size_t i = 0; i < installer_index.num_registered; i++) {
+ struct installer *installer = installer_index.installers[i];
+
+ if ((installer->install_type == install_type) &&
+ (installer->location_id == location_id)) {
+ result = installer;
+ break;
+ }
+ }
+
+ return result;
+}
+
+struct installer *installer_index_find_by_location_uuid(const struct uuid_octets *location_uuid)
+{
+ struct installer *result = NULL;
+
+ for (size_t i = 0; i < installer_index.num_registered; i++) {
+ struct installer *installer = installer_index.installers[i];
+
+ if (uuid_is_equal(location_uuid->octets, installer->location_uuid.octets)) {
+ result = installer;
+ break;
+ }
+ }
+
+ return result;
+}
+
+struct installer *installer_index_get(unsigned int index)
+{
+ struct installer *result = NULL;
+
+ if (index < installer_index.num_registered)
+ result = installer_index.installers[index];
+
+ return result;
+}
+
+const uint32_t *installer_index_get_location_ids(size_t *num_ids)
+{
+ *num_ids = installer_index.num_location_ids;
+ return installer_index.location_ids;
+}
diff --git a/components/service/fwu/installer/installer_index.h b/components/service/fwu/installer/installer_index.h
new file mode 100644
index 000000000..81ad05d10
--- /dev/null
+++ b/components/service/fwu/installer/installer_index.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INSTALLER_INDEX_H
+#define INSTALLER_INDEX_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "service/fwu/agent/install_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct installer;
+struct uuid_octets;
+
+/**
+ * @brief Initialize the installer index
+ *
+ * The installer_index is a singleton that holds the set of installers that are suitable
+ * for the deployment. The mix of installers will depend on factors such as the image
+ * container used by firmware or whether images are encrypted etc.
+ */
+void installer_index_init(void);
+
+/**
+ * @brief Clears the installer index
+ *
+ * Clears all mappings.
+ */
+void installer_index_clear(void);
+
+/**
+ * @brief Register an installer
+ *
+ * Registers an installer to handle image installation for a particular install_type
+ * and location.
+ *
+ * @param[in] installer The installer to use
+ */
+void installer_index_register(struct installer *installer);
+
+/**
+ * @brief Find an installer for the specified type and location
+ *
+ * @param[in] install_type The type of installer
+ * @param[in] location_id The location it serves
+ *
+ * @return Pointer to a concrete installer or NULL if none found
+ */
+struct installer *installer_index_find(enum install_type install_type, uint32_t location_id);
+
+/**
+ * @brief Find a registered installer associated with the specified location UUID
+ *
+ * @param[in] location_uuid The associated location UUID
+ *
+ * @return Pointer to a concrete installer or NULL if none found
+ */
+struct installer *installer_index_find_by_location_uuid(const struct uuid_octets *location_uuid);
+
+/**
+ * @brief Iterator function
+ *
+ * @param[in] index 0..n
+ *
+ * @return Pointer to a concrete installer or NULL if iterated beyond final entry
+ */
+struct installer *installer_index_get(unsigned int index);
+
+/**
+ * @brief Get an array of location_ids
+ *
+ * Updatable firmware may be distributed over multiple locations. Each location is
+ * assigned a location_id when the set of installers are registered for the platform.
+ * This function returns a variable length array of locations_ids for the platform.
+ * This is useful for checking if an incoming update has included components that
+ * update all locations or not.
+ *
+ * @param[out] num_ids 0..n
+ *
+ * @return Pointer to a static array of location ids
+ */
+const uint32_t *installer_index_get_location_ids(size_t *num_ids);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INSTALLER_INDEX_H */
diff --git a/components/service/fwu/installer/raw/component.cmake b/components/service/fwu/installer/raw/component.cmake
new file mode 100644
index 000000000..47c4cbb9e
--- /dev/null
+++ b/components/service/fwu/installer/raw/component.cmake
@@ -0,0 +1,16 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/raw_installer.c"
+ )
+
+target_compile_definitions(${TGT} PRIVATE
+ RAW_INSTALLER_AVAILABLE) \ No newline at end of file
diff --git a/components/service/fwu/installer/raw/raw_installer.c b/components/service/fwu/installer/raw/raw_installer.c
new file mode 100644
index 000000000..0002779eb
--- /dev/null
+++ b/components/service/fwu/installer/raw/raw_installer.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "raw_installer.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "media/volume/index/volume_index.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/agent/fw_directory.h"
+
+static int raw_installer_begin(void *context, unsigned int current_volume_id,
+ unsigned int update_volume_id)
+{
+ struct raw_installer *subject = (struct raw_installer *)context;
+
+ (void)current_volume_id;
+
+ int status = volume_index_find(update_volume_id, &subject->target_volume);
+
+ if (status == 0) {
+ assert(subject->target_volume);
+
+ subject->commit_count = 0;
+ subject->is_open = false;
+ }
+
+ return status;
+}
+
+static int raw_installer_finalize(void *context)
+{
+ struct raw_installer *subject = (struct raw_installer *)context;
+
+ /* Close volume if left open */
+ if (subject->is_open) {
+ assert(subject->target_volume);
+
+ volume_close(subject->target_volume);
+ subject->is_open = false;
+ }
+
+ return FWU_STATUS_SUCCESS;
+}
+
+static void raw_installer_abort(void *context)
+{
+ raw_installer_finalize(context);
+}
+
+static int raw_installer_open(void *context, const struct image_info *image_info)
+{
+ struct raw_installer *subject = (struct raw_installer *)context;
+ int status = FWU_STATUS_DENIED;
+
+ /* Because the raw_installer uses a single image to update the
+ * target volume, it only makes sense to commit a single image
+ * during an update transaction. Defend against the case where
+ * an input update package contains more than one raw image to
+ * install into a particular location.
+ */
+ if (!subject->is_open && subject->commit_count < 1) {
+ assert(subject->target_volume);
+
+ status = volume_open(subject->target_volume);
+
+ if (!status) {
+ /* Prior to writing to the volume to install the image, ensure
+ * that the volume is erased.
+ */
+ status = volume_erase(subject->target_volume);
+
+ if (!status) {
+ subject->is_open = true;
+ subject->bytes_written = 0;
+ } else {
+ /* Failed to erase */
+ volume_close(subject->target_volume);
+ }
+ }
+ }
+
+ return status;
+}
+
+static int raw_installer_commit(void *context)
+{
+ struct raw_installer *subject = (struct raw_installer *)context;
+ int status = FWU_STATUS_DENIED;
+
+ if (subject->is_open) {
+ assert(subject->target_volume);
+
+ status = volume_close(subject->target_volume);
+
+ ++subject->commit_count;
+ subject->is_open = false;
+
+ if (!status && !subject->bytes_written) {
+ /* Installing a zero length image can imply an image delete
+ * operation. For certain types of installer, this is a legitimate
+ * operation. For a raw_installer, there really is no way to
+ * delete an image so return an error if an attempt was made.
+ */
+ status = FWU_STATUS_NOT_AVAILABLE;
+ }
+ }
+
+ return status;
+}
+
+static int raw_installer_write(void *context, const uint8_t *data, size_t data_len)
+{
+ struct raw_installer *subject = (struct raw_installer *)context;
+ int status = FWU_STATUS_DENIED;
+
+ if (subject->is_open) {
+ assert(subject->target_volume);
+
+ size_t len_written = 0;
+
+ status = volume_write(subject->target_volume, (const uintptr_t)data, data_len,
+ &len_written);
+
+ subject->bytes_written += len_written;
+
+ /* Check for the volume full condition where not all the requested
+ * data was written.
+ */
+ if (!status && (len_written != data_len))
+ status = FWU_STATUS_OUT_OF_BOUNDS;
+ }
+
+ return status;
+}
+
+static int raw_installer_enumerate(void *context, uint32_t volume_id,
+ struct fw_directory *fw_directory)
+{
+ struct raw_installer *subject = (struct raw_installer *)context;
+ struct volume *volume = NULL;
+
+ int status = volume_index_find(volume_id, &volume);
+
+ if (status != 0)
+ return status;
+
+ assert(volume);
+
+ /* Found the active volume so query it for information in order to
+ * prepare an entry in the fw_directory to represent the whole volume
+ * as an advertised updatable image.
+ */
+ struct image_info image_info = { 0 };
+
+ /* Limit the advertised max size to the volume size. The volume needs
+ * to be open to query its size.
+ */
+ if (!subject->is_open) {
+ /* Open if necessary */
+ status = volume_open(volume);
+ if (status != 0)
+ return status;
+ }
+
+ status = volume_size(volume, &image_info.max_size);
+ if (status != 0)
+ return status;
+
+ if (!subject->is_open) {
+ /* Leave volume in the same open state */
+ status = volume_close(volume);
+ if (status)
+ return status;
+ }
+
+ /* These attributes will have been assigned during platform configuration */
+ image_info.img_type_uuid = subject->base_installer.location_uuid;
+ image_info.location_id = subject->base_installer.location_id;
+ image_info.install_type = subject->base_installer.install_type;
+
+ status = fw_directory_add_image_info(fw_directory, &image_info);
+
+ return status;
+}
+
+void raw_installer_init(struct raw_installer *subject, const struct uuid_octets *location_uuid,
+ uint32_t location_id)
+{
+ /* Define concrete installer interface */
+ static const struct installer_interface interface = {
+ raw_installer_begin, raw_installer_finalize, raw_installer_abort,
+ raw_installer_open, raw_installer_commit, raw_installer_write,
+ raw_installer_enumerate
+ };
+
+ /* Initialize base installer - a raw_installer is a type of
+ * installer that always updates a whole volume.
+ */
+ installer_init(&subject->base_installer, INSTALL_TYPE_WHOLE_VOLUME, location_id,
+ location_uuid, subject, &interface);
+
+ /* Initialize raw_installer specifics */
+ subject->target_volume = NULL;
+ subject->commit_count = 0;
+ subject->bytes_written = 0;
+ subject->is_open = false;
+}
+
+void raw_installer_deinit(struct raw_installer *subject)
+{
+ (void)subject;
+}
diff --git a/components/service/fwu/installer/raw/raw_installer.h b/components/service/fwu/installer/raw/raw_installer.h
new file mode 100644
index 000000000..51b7354a7
--- /dev/null
+++ b/components/service/fwu/installer/raw/raw_installer.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FWU_RAW_INSTALLER_H
+#define FWU_RAW_INSTALLER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "common/uuid/uuid.h"
+#include "media/volume/volume.h"
+#include "service/fwu/installer/installer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief raw_installer structure definition
+ *
+ * A raw_installer is an installer that takes the raw input image and writes
+ * it directly to the target storage volume with no intermediate processing.
+ * The raw_installer can be used for say installing a complete firmware image
+ * into a single volume. Because the raw_installer has no knowledge of the
+ * format of images that it installs, the assigned location_uuid is used
+ * by the enumerate method to advertise a single updatable image that
+ * corresponds to the entire raw contents of the associated target
+ * volume. Other sub-volume installers may advertise additional updatable
+ * images that reside within the same target volume.
+ */
+struct raw_installer {
+ struct installer base_installer;
+ struct volume *target_volume;
+ unsigned int commit_count;
+ size_t bytes_written;
+ bool is_open;
+};
+
+/**
+ * \brief Initialize a raw_installer
+ *
+ * \param[in] subject The subject raw_installer
+ * \param[in] location_uuid The associated location UUID
+ * \param[in] location_id Identifies where to install qualifying images
+ */
+void raw_installer_init(struct raw_installer *subject, const struct uuid_octets *location_uuid,
+ uint32_t location_id);
+
+/**
+ * \brief De-initialize a raw_installer
+ *
+ * \param[in] subject The subject raw_installer
+ */
+void raw_installer_deinit(struct raw_installer *subject);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FWU_RAW_INSTALLER_H */
diff --git a/components/service/fwu/installer/raw/test/component.cmake b/components/service/fwu/installer/raw/test/component.cmake
new file mode 100644
index 000000000..adda59ca0
--- /dev/null
+++ b/components/service/fwu/installer/raw/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/raw_installer_tests.cpp"
+ )
diff --git a/components/service/fwu/installer/raw/test/raw_installer_tests.cpp b/components/service/fwu/installer/raw/test/raw_installer_tests.cpp
new file mode 100644
index 000000000..18c265472
--- /dev/null
+++ b/components/service/fwu/installer/raw/test/raw_installer_tests.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <cstdlib>
+#include <cstring>
+
+#include "common/uuid/uuid.h"
+#include "media/disk/guid.h"
+#include "media/volume/block_volume/block_volume.h"
+#include "media/volume/index/volume_index.h"
+#include "media/volume/volume.h"
+#include "service/block_storage/config/ref/ref_partition_configurator.h"
+#include "service/block_storage/factory/ref_ram_gpt/block_store_factory.h"
+#include "service/fwu/agent/fw_directory.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+#include "service/fwu/installer/installer_index.h"
+#include "service/fwu/installer/raw/raw_installer.h"
+
+TEST_GROUP(FwuRawInstallerTests)
+{
+ void setup()
+ {
+ int result;
+ struct uuid_octets partition_guid;
+
+ m_image = NULL;
+
+ installer_index_init();
+ volume_index_init();
+
+ /* Use the reference disk configuration and use partition 1 & 2 as
+ * storage for A and B firmware banks.
+ */
+ m_block_store = ref_ram_gpt_block_store_factory_create();
+
+ /* Construct fw volume A */
+ uuid_guid_octets_from_canonical(&partition_guid, REF_PARTITION_1_GUID);
+
+ result = block_volume_init(&m_block_volume_a, m_block_store, &partition_guid,
+ &m_fw_volume_a);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_fw_volume_a);
+
+ /* Construct fw volume B */
+ uuid_guid_octets_from_canonical(&partition_guid, REF_PARTITION_2_GUID);
+
+ result = block_volume_init(&m_block_volume_b, m_block_store, &partition_guid,
+ &m_fw_volume_b);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_fw_volume_b);
+
+ /* Prepare an image_info structure to describe the image to
+ * install. In a complete integration, this will come from the
+ * fw_directory.
+ */
+ uuid_guid_octets_from_canonical(&m_image_info.img_type_uuid,
+ "1c22ca2c-9732-49e6-ba3b-eed40e27fda3");
+
+ m_image_info.max_size =
+ (REF_PARTITION_1_ENDING_LBA - REF_PARTITION_1_STARTING_LBA + 1) *
+ REF_PARTITION_BLOCK_SIZE;
+ m_image_info.lowest_accepted_version = 1;
+ m_image_info.active_version = 1;
+ m_image_info.permissions = 0;
+ m_image_info.image_index = 0;
+ m_image_info.location_id = FW_STORE_LOCATION_ID;
+ m_image_info.install_type = INSTALL_TYPE_WHOLE_VOLUME;
+
+ /* Mimic a platform configuration where storage volumes are assigned
+ * location and usage IDs. These usage IDs correspond to an A/B banked
+ * firmware store. Multiple locations could be configured here
+ * but for these tests, there is only one. This enables the generic
+ * banked_fw_store to be completely decoupled from the details
+ * of which fw volumes need updating on a platform.
+ */
+ volume_index_add(banked_volume_id(FW_STORE_LOCATION_ID, BANKED_USAGE_ID_FW_BANK_A),
+ m_fw_volume_a);
+ volume_index_add(banked_volume_id(FW_STORE_LOCATION_ID, BANKED_USAGE_ID_FW_BANK_B),
+ m_fw_volume_b);
+
+ /* A platform configuration will also determine which installers are
+ * assigned to which locations. This provides flexibility to configure
+ * appropriate installers to handle alternative fw packages and installation
+ * strategies.
+ */
+ raw_installer_init(&m_installer, &m_image_info.img_type_uuid, FW_STORE_LOCATION_ID);
+
+ installer_index_register(&m_installer.base_installer);
+ }
+
+ void teardown()
+ {
+ delete[] m_image;
+
+ raw_installer_deinit(&m_installer);
+
+ installer_index_clear();
+ volume_index_clear();
+
+ block_volume_deinit(&m_block_volume_a);
+ block_volume_deinit(&m_block_volume_b);
+ ref_ram_gpt_block_store_factory_destroy(m_block_store);
+ }
+
+ void create_image(size_t len)
+ {
+ m_image = new uint8_t[len];
+ m_image_len = len;
+
+ for (size_t i = 0; i < len; i++)
+ m_image[i] = (uint8_t)rand();
+ }
+
+ int write_image_in_random_len_chunks(struct installer * installer)
+ {
+ int status = 0;
+ size_t bytes_written = 0;
+
+ while ((bytes_written < m_image_len) && !status) {
+ size_t write_len = rand() % 100 + 1;
+
+ if ((bytes_written + write_len) > m_image_len)
+ write_len = m_image_len - bytes_written;
+
+ status = installer_write(installer, &m_image[bytes_written], write_len);
+ bytes_written += write_len;
+ }
+
+ return status;
+ }
+
+ void check_update_installed(struct volume * volume)
+ {
+ int status = 0;
+ size_t total_read = 0;
+ uintptr_t file_handle = 0;
+
+ status = io_open(volume->dev_handle, volume->io_spec, &file_handle);
+ LONGS_EQUAL(0, status);
+
+ while (total_read < m_image_len) {
+ uint8_t read_buf[1000];
+ size_t len_read = 0;
+ size_t bytes_remaining = m_image_len - total_read;
+ size_t req_len = (bytes_remaining > sizeof(read_buf)) ? sizeof(read_buf) :
+ bytes_remaining;
+
+ memset(read_buf, 0, sizeof(read_buf));
+
+ status = io_read(file_handle, (uintptr_t)read_buf, req_len, &len_read);
+ LONGS_EQUAL(0, status);
+ UNSIGNED_LONGS_EQUAL(req_len, len_read);
+
+ MEMCMP_EQUAL(&m_image[total_read], read_buf, len_read);
+
+ total_read += len_read;
+ }
+
+ io_close(file_handle);
+ }
+
+ static const unsigned int FW_STORE_LOCATION_ID = 0x100;
+
+ struct block_store *m_block_store;
+ struct block_volume m_block_volume_a;
+ struct block_volume m_block_volume_b;
+ struct volume *m_fw_volume_a;
+ struct volume *m_fw_volume_b;
+ struct raw_installer m_installer;
+ struct image_info m_image_info;
+ uint8_t *m_image;
+ size_t m_image_len;
+};
+
+TEST(FwuRawInstallerTests, normalInstallFlow)
+{
+ int status = 0;
+
+ /* Create arbitrary length image that should easily fit into the destination partition */
+ create_image(REF_PARTITION_BLOCK_SIZE * 2 + 111);
+
+ /* Expect to find a suitable installer for the given image_info */
+ struct installer *installer =
+ installer_index_find(m_image_info.install_type, m_image_info.location_id);
+ CHECK_TRUE(installer);
+ UNSIGNED_LONGS_EQUAL(FW_STORE_LOCATION_ID, installer->location_id);
+
+ /* Begin installation transaction - installing into volume A */
+ status = installer_begin(installer,
+ banked_volume_id(FW_STORE_LOCATION_ID,
+ BANKED_USAGE_ID_FW_BANK_B), /* Current volume */
+ banked_volume_id(FW_STORE_LOCATION_ID,
+ BANKED_USAGE_ID_FW_BANK_A)); /* Update volume */
+ LONGS_EQUAL(0, status);
+
+ /* Open install stream */
+ status = installer_open(installer, &m_image_info);
+ LONGS_EQUAL(0, status);
+
+ /* Stream the update image into the installer */
+ status = write_image_in_random_len_chunks(installer);
+ LONGS_EQUAL(0, status);
+
+ /* Commit after writing all image data */
+ status = installer_commit(installer);
+ LONGS_EQUAL(0, status);
+
+ /* Finalize installation transaction */
+ status = installer_finalize(installer);
+ LONGS_EQUAL(0, status);
+
+ /* Expect the update volume to contain the update */
+ check_update_installed(m_fw_volume_a);
+}
diff --git a/components/service/fwu/provider/component.cmake b/components/service/fwu/provider/component.cmake
new file mode 100644
index 000000000..bf15460fe
--- /dev/null
+++ b/components/service/fwu/provider/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_provider.c"
+ )
diff --git a/components/service/fwu/provider/fwu_provider.c b/components/service/fwu/provider/fwu_provider.c
new file mode 100644
index 000000000..e94f65379
--- /dev/null
+++ b/components/service/fwu/provider/fwu_provider.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fwu_provider.h"
+
+#include <stddef.h>
+
+#include "common/uuid/uuid.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "protocols/service/fwu/packed-c/opcodes.h"
+#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/provider/serializer/fwu_provider_serializer.h"
+#include "fwu_uuid.h"
+
+/* Service request handlers */
+static rpc_status_t begin_staging_handler(void *context, struct rpc_request *req);
+static rpc_status_t end_staging_handler(void *context, struct rpc_request *req);
+static rpc_status_t cancel_staging_handler(void *context, struct rpc_request *req);
+static rpc_status_t open_handler(void *context, struct rpc_request *req);
+static rpc_status_t write_stream_handler(void *context, struct rpc_request *req);
+static rpc_status_t read_stream_handler(void *context, struct rpc_request *req);
+static rpc_status_t commit_handler(void *context, struct rpc_request *req);
+static rpc_status_t accept_image_handler(void *context, struct rpc_request *req);
+static rpc_status_t select_previous_handler(void *context, struct rpc_request *req);
+
+/* Handler mapping table for service */
+static const struct service_handler handler_table[] = {
+ { TS_FWU_OPCODE_BEGIN_STAGING, begin_staging_handler },
+ { TS_FWU_OPCODE_END_STAGING, end_staging_handler },
+ { TS_FWU_OPCODE_CANCEL_STAGING, cancel_staging_handler },
+ { TS_FWU_OPCODE_OPEN, open_handler },
+ { TS_FWU_OPCODE_WRITE_STREAM, write_stream_handler },
+ { TS_FWU_OPCODE_READ_STREAM, read_stream_handler },
+ { TS_FWU_OPCODE_COMMIT, commit_handler },
+ { TS_FWU_OPCODE_ACCEPT_IMAGE, accept_image_handler },
+ { TS_FWU_OPCODE_SELECT_PREVIOUS, select_previous_handler }
+};
+
+struct rpc_service_interface *fwu_provider_init(struct fwu_provider *context,
+ struct update_agent *update_agent)
+{
+ const struct rpc_uuid service_uuid = { .uuid = TS_FWU_SERVICE_UUID };
+ /* Initialise the fwu_provider */
+ context->update_agent = update_agent;
+
+ for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
+ context->serializers[encoding] = NULL;
+
+ service_provider_init(&context->base_provider, context, &service_uuid, handler_table,
+ sizeof(handler_table) / sizeof(struct service_handler));
+
+ return service_provider_get_rpc_interface(&context->base_provider);
+}
+
+void fwu_provider_deinit(struct fwu_provider *context)
+{
+ (void)context;
+}
+
+void fwu_provider_register_serializer(struct fwu_provider *context, unsigned int encoding,
+ const struct fwu_provider_serializer *serializer)
+{
+ if (encoding < TS_RPC_ENCODING_LIMIT) {
+ context->serializers[encoding] = serializer;
+ }
+}
+
+static const struct fwu_provider_serializer *get_fwu_serializer(struct fwu_provider *this_instance,
+ const struct rpc_request *req)
+{
+ const struct fwu_provider_serializer *serializer = NULL;
+ unsigned int encoding = 0;
+
+ if (encoding < TS_RPC_ENCODING_LIMIT)
+ serializer = this_instance->serializers[encoding];
+
+ return serializer;
+}
+
+static rpc_status_t begin_staging_handler(void *context, struct rpc_request *req)
+{
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+
+ req->service_status = update_agent_begin_staging(this_instance->update_agent);
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t end_staging_handler(void *context, struct rpc_request *req)
+{
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+
+ req->service_status = update_agent_end_staging(this_instance->update_agent);
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t cancel_staging_handler(void *context, struct rpc_request *req)
+{
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+
+ req->service_status = update_agent_cancel_staging(this_instance->update_agent);
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t open_handler(void *context, struct rpc_request *req)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ struct uuid_octets image_type_uuid;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_open_req(req_buf, &image_type_uuid);
+
+ if (rpc_status == RPC_SUCCESS) {
+ uint32_t handle = 0;
+ req->service_status =
+ update_agent_open(this_instance->update_agent, &image_type_uuid, &handle);
+
+ if (!req->service_status) {
+ struct rpc_buffer *resp_buf = &req->response;
+ rpc_status = serializer->serialize_open_resp(resp_buf, handle);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t write_stream_handler(void *context, struct rpc_request *req)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ uint32_t handle = 0;
+ size_t data_len = 0;
+ const uint8_t *data = NULL;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_write_stream_req(req_buf, &handle, &data_len,
+ &data);
+
+ if (rpc_status == RPC_SUCCESS) {
+ req->service_status = update_agent_write_stream(this_instance->update_agent, handle,
+ data, data_len);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t read_stream_handler(void *context, struct rpc_request *req)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ uint32_t handle = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_read_stream_req(req_buf, &handle);
+
+ if (rpc_status == RPC_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
+ uint8_t *payload_buf;
+ size_t max_payload;
+ size_t read_len = 0;
+ size_t total_len = 0;
+
+ serializer->read_stream_resp_payload(resp_buf, &payload_buf, &max_payload);
+
+ req->service_status = update_agent_read_stream(this_instance->update_agent, handle,
+ payload_buf, max_payload, &read_len,
+ &total_len);
+
+ if (!req->service_status)
+ rpc_status = serializer->serialize_read_stream_resp(resp_buf, read_len,
+ total_len);
+
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t commit_handler(void *context, struct rpc_request *req)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ uint32_t handle = 0;
+ bool accepted = false;
+ size_t max_atomic_len = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_commit_req(req_buf, &handle, &accepted,
+ &max_atomic_len);
+
+ if (rpc_status == RPC_SUCCESS) {
+ req->service_status = update_agent_commit(this_instance->update_agent, handle,
+ accepted);
+
+ if (!req->service_status) {
+ struct rpc_buffer *resp_buf = &req->response;
+ rpc_status = serializer->serialize_commit_resp(resp_buf, 0, 0);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t accept_image_handler(void *context, struct rpc_request *req)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_buffer *req_buf = &req->request;
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ struct uuid_octets image_type_uuid;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_accept_req(req_buf, &image_type_uuid);
+
+ if (rpc_status == RPC_SUCCESS)
+ req->service_status = update_agent_accept(this_instance->update_agent,
+ &image_type_uuid);
+
+ return rpc_status;
+}
+
+static rpc_status_t select_previous_handler(void *context, struct rpc_request *req)
+{
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+
+ req->service_status = update_agent_select_previous(this_instance->update_agent);
+
+ return RPC_SUCCESS;
+}
diff --git a/components/service/fwu/provider/fwu_provider.h b/components/service/fwu/provider/fwu_provider.h
new file mode 100644
index 000000000..037889a4b
--- /dev/null
+++ b/components/service/fwu/provider/fwu_provider.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_PROVIDER_H
+#define FWU_PROVIDER_H
+
+#include "protocols/rpc/common/packed-c/encoding.h"
+#include "rpc/common/endpoint/rpc_service_interface.h"
+#include "service/common/provider/service_provider.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct fwu_provider_serializer;
+struct update_agent;
+
+/**
+ * \brief fwu_provider instance structure
+ *
+ * An instance of the fwu_provider presents the service level interface for
+ * remote access to the fwu service. In addition to handling incoming call
+ * requests, the fwu_provider is responsible for access control, call parameter
+ * serialization/deserialization and parameter sanitation. Request are delegated
+ * to the associated update_agent.
+ */
+struct fwu_provider {
+ struct service_provider base_provider;
+ const struct fwu_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
+ struct update_agent *update_agent;
+};
+
+/**
+ * \brief Initialise a fwu_provider
+ *
+ * \param[in] context The subject fwu_provider context
+ * \param[in] update_agent The associated update_agent
+ *
+ * \return A pointer to the exposed rpc_interface or NULL on failure
+ */
+struct rpc_service_interface *fwu_provider_init(struct fwu_provider *context,
+ struct update_agent *update_agent);
+
+/**
+ * \brief De-initialise a fwu_provider
+ *
+ * \param[in] context The subject fwu_provider context
+ */
+void fwu_provider_deinit(struct fwu_provider *context);
+
+/**
+ * \brief Register a serializer
+ *
+ * \param[in] context The subject fwu_provider context
+ * \param[in] encoding The encoding scheme
+ * \param[in] serializer The serializer
+ */
+void fwu_provider_register_serializer(struct fwu_provider *context, unsigned int encoding,
+ const struct fwu_provider_serializer *serializer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FWU_PROVIDER_H */
diff --git a/components/service/fwu/provider/fwu_uuid.h b/components/service/fwu/provider/fwu_uuid.h
new file mode 100644
index 000000000..4fe477679
--- /dev/null
+++ b/components/service/fwu/provider/fwu_uuid.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_UUID_H
+#define FWU_UUID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TS_FWU_SERVICE_UUID \
+{ 0x68, 0x23, 0xa8, 0x38, 0x1b, 0x06, 0x47, 0x0e, 0x97, 0x74, 0x0c, 0xce, 0x8b, 0xfb, 0x53, 0xfd }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FWU_UUID_H */
diff --git a/components/service/fwu/provider/serializer/fwu_provider_serializer.h b/components/service/fwu/provider/serializer/fwu_provider_serializer.h
new file mode 100644
index 000000000..c9df1941d
--- /dev/null
+++ b/components/service/fwu/provider/serializer/fwu_provider_serializer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_PROVIDER_SERIALIZER_H
+#define FWU_PROVIDER_SERIALIZER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "common/uuid/uuid.h"
+#include "rpc/common/endpoint/rpc_service_interface.h"
+
+/* Provides a common interface for parameter serialization operations
+ * for the fwu service provider. Allows alternative serialization
+ * protocols to be used without hard-wiring a particular protocol
+ * into the service provider code. A concrete serializer must
+ * implement this interface.
+ */
+struct fwu_provider_serializer {
+ /* Operation: open */
+ rpc_status_t (*deserialize_open_req)(const struct rpc_buffer *req_buf,
+ struct uuid_octets *image_type_uuid);
+
+ rpc_status_t (*serialize_open_resp)(struct rpc_buffer *resp_buf, uint32_t handle);
+
+ /* Operation: write_stream */
+ rpc_status_t (*deserialize_write_stream_req)(const struct rpc_buffer *req_buf,
+ uint32_t *handle, size_t *data_len,
+ const uint8_t **data);
+
+ /* Operation: read_stream */
+ rpc_status_t (*deserialize_read_stream_req)(const struct rpc_buffer *req_buf,
+ uint32_t *handle);
+
+ void (*read_stream_resp_payload)(const struct rpc_buffer *resp_buf,
+ uint8_t **payload_buf, size_t *max_payload);
+
+ rpc_status_t (*serialize_read_stream_resp)(struct rpc_buffer *resp_buf,
+ size_t read_bytes, size_t total_bytes);
+
+ /* Operation: commit */
+ rpc_status_t (*deserialize_commit_req)(const struct rpc_buffer *req_buf,
+ uint32_t *handle, bool *accepted,
+ size_t *max_atomic_len);
+
+ rpc_status_t (*serialize_commit_resp)(struct rpc_buffer *resp_buf, size_t progress,
+ size_t total_work);
+
+ /* Operation: accept_image */
+ rpc_status_t (*deserialize_accept_req)(const struct rpc_buffer *req_buf,
+ struct uuid_octets *image_type_uuid);
+};
+
+#endif /* FWU_PROVIDER_SERIALIZER_H */
diff --git a/components/service/fwu/provider/serializer/packed-c/component.cmake b/components/service/fwu/provider/serializer/packed-c/component.cmake
new file mode 100644
index 000000000..4209cae89
--- /dev/null
+++ b/components/service/fwu/provider/serializer/packed-c/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/packedc_fwu_provider_serializer.c"
+ )
diff --git a/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.c b/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.c
new file mode 100644
index 000000000..cb013d400
--- /dev/null
+++ b/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "packedc_fwu_provider_serializer.h"
+
+#include <string.h>
+
+#include "protocols/rpc/common/packed-c/status.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+
+static rpc_status_t deserialize_open_req(const struct rpc_buffer *req_buf,
+ struct uuid_octets *image_type_uuid)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_open_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ const struct ts_fwu_open_in *recv_msg =
+ (const struct ts_fwu_open_in *)req_buf->data;
+
+ memcpy(image_type_uuid->octets, recv_msg->image_type_uuid, UUID_OCTETS_LEN);
+
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t serialize_open_resp(struct rpc_buffer *resp_buf, uint32_t handle)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ size_t fixed_len = sizeof(struct ts_fwu_open_out);
+
+ if (fixed_len <= resp_buf->size) {
+ struct ts_fwu_open_out *resp_msg = (struct ts_fwu_open_out *)resp_buf->data;
+
+ resp_msg->handle = handle;
+
+ resp_buf->data_length = fixed_len;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: write_stream */
+static rpc_status_t deserialize_write_stream_req(const struct rpc_buffer *req_buf,
+ uint32_t *handle, size_t *data_length,
+ const uint8_t **data)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_write_stream_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ const struct ts_fwu_write_stream_in *recv_msg =
+ (const struct ts_fwu_write_stream_in *)req_buf->data;
+
+ *handle = recv_msg->handle;
+ *data_length = recv_msg->data_len;
+ *data = recv_msg->payload;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: read_stream */
+static rpc_status_t deserialize_read_stream_req(const struct rpc_buffer *req_buf,
+ uint32_t *handle)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_read_stream_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ const struct ts_fwu_read_stream_in *recv_msg =
+ (const struct ts_fwu_read_stream_in *)req_buf->data;
+
+ *handle = recv_msg->handle;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+static void read_stream_resp_payload(const struct rpc_buffer *resp_buf, uint8_t **payload_buf,
+ size_t *max_payload)
+{
+ struct ts_fwu_read_stream_out *resp_msg = (struct ts_fwu_read_stream_out *)resp_buf->data;
+ size_t fixed_len = offsetof(struct ts_fwu_read_stream_out, payload);
+
+ *max_payload = 0;
+ *payload_buf = resp_msg->payload;
+
+ if (fixed_len < resp_buf->size)
+ *max_payload = resp_buf->size - fixed_len;
+}
+
+static rpc_status_t serialize_read_stream_resp(struct rpc_buffer *resp_buf, size_t read_bytes,
+ size_t total_bytes)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_fwu_read_stream_out *resp_msg = (struct ts_fwu_read_stream_out *)resp_buf->data;
+ size_t proto_overhead = offsetof(struct ts_fwu_read_stream_out, payload);
+
+ if (read_bytes > (SIZE_MAX - proto_overhead))
+ return RPC_ERROR_INVALID_VALUE;
+
+ size_t required_len = proto_overhead + read_bytes;
+
+ if (required_len <= resp_buf->size) {
+ resp_msg->read_bytes = read_bytes;
+ resp_msg->total_bytes = total_bytes;
+
+ resp_buf->data_length = required_len;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: commit */
+static rpc_status_t deserialize_commit_req(const struct rpc_buffer *req_buf, uint32_t *handle,
+ bool *accepted, size_t *max_atomic_len)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_commit_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ const struct ts_fwu_commit_in *recv_msg =
+ (const struct ts_fwu_commit_in *)req_buf->data;
+
+ *handle = recv_msg->handle;
+ *accepted = (recv_msg->acceptance_req == 0);
+ *max_atomic_len = recv_msg->max_atomic_len;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t serialize_commit_resp(struct rpc_buffer *resp_buf, size_t progress,
+ size_t total_work)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct ts_fwu_commit_out *resp_msg = (struct ts_fwu_commit_out *)resp_buf->data;
+
+ size_t required_len = sizeof(struct ts_fwu_commit_out);
+
+ if (required_len <= resp_buf->size) {
+ resp_msg->progress = progress;
+ resp_msg->total_work = total_work;
+
+ resp_buf->data_length = required_len;
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: accept_image */
+static rpc_status_t deserialize_accept_req(const struct rpc_buffer *req_buf,
+ struct uuid_octets *image_type_uuid)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_accept_image_in);
+
+ if (expected_fixed_len <= req_buf->data_length) {
+ const struct ts_fwu_accept_image_in *recv_msg =
+ (const struct ts_fwu_accept_image_in *)req_buf->data;
+
+ memcpy(image_type_uuid->octets, recv_msg->image_type_uuid, UUID_OCTETS_LEN);
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
+/* Singleton method to provide access to the serializer instance */
+const struct fwu_provider_serializer *packedc_fwu_provider_serializer_instance(void)
+{
+ static const struct fwu_provider_serializer instance = {
+ deserialize_open_req, serialize_open_resp, deserialize_write_stream_req,
+ deserialize_read_stream_req, read_stream_resp_payload, serialize_read_stream_resp,
+ deserialize_commit_req, serialize_commit_resp, deserialize_accept_req
+ };
+
+ return &instance;
+}
diff --git a/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h b/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h
new file mode 100644
index 000000000..e1baeed0a
--- /dev/null
+++ b/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_FWU_PROVIDER_SERIALIZER_H
+#define PACKEDC_FWU_PROVIDER_SERIALIZER_H
+
+#include "service/fwu/provider/serializer/fwu_provider_serializer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Singleton method to provide access to the packed-c serializer
+ * for the fwu service provider.
+ */
+const struct fwu_provider_serializer *packedc_fwu_provider_serializer_instance(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PACKEDC_FWU_PROVIDER_SERIALIZER_H */
diff --git a/components/service/fwu/test/fwu_client/direct/component.cmake b/components/service/fwu/test/fwu_client/direct/component.cmake
new file mode 100644
index 000000000..b9bbe1b71
--- /dev/null
+++ b/components/service/fwu/test/fwu_client/direct/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/direct_fwu_client.cpp"
+ )
diff --git a/components/service/fwu/test/fwu_client/direct/direct_fwu_client.cpp b/components/service/fwu/test/fwu_client/direct/direct_fwu_client.cpp
new file mode 100644
index 000000000..6afd0f294
--- /dev/null
+++ b/components/service/fwu/test/fwu_client/direct/direct_fwu_client.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "direct_fwu_client.h"
+
+#include <cstring>
+
+#include "service/fwu/agent/update_agent.h"
+
+direct_fwu_client::direct_fwu_client(struct update_agent *update_agent)
+ : fwu_client()
+ , m_update_agent(update_agent)
+ , m_read_buf()
+{
+ /* The read buffer represents a communication buffer that will
+ * constrain the amount of data that may be read in a single read.
+ */
+ memset(m_read_buf, 0, READ_BUF_SIZE);
+}
+
+direct_fwu_client::~direct_fwu_client()
+{
+}
+
+int direct_fwu_client::begin_staging(void)
+{
+ return update_agent_begin_staging(m_update_agent);
+}
+
+int direct_fwu_client::end_staging(void)
+{
+ return update_agent_end_staging(m_update_agent);
+}
+
+int direct_fwu_client::cancel_staging(void)
+{
+ return update_agent_cancel_staging(m_update_agent);
+}
+
+int direct_fwu_client::accept(const struct uuid_octets *image_type_uuid)
+{
+ return update_agent_accept(m_update_agent, image_type_uuid);
+}
+
+int direct_fwu_client::select_previous(void)
+{
+ return update_agent_select_previous(m_update_agent);
+}
+
+int direct_fwu_client::open(const struct uuid_octets *uuid, uint32_t *handle)
+{
+ return update_agent_open(m_update_agent, uuid, handle);
+}
+
+int direct_fwu_client::commit(uint32_t handle, bool accepted)
+{
+ return update_agent_commit(m_update_agent, handle, accepted);
+}
+
+int direct_fwu_client::write_stream(uint32_t handle, const uint8_t *data, size_t data_len)
+{
+ return update_agent_write_stream(m_update_agent, handle, data, data_len);
+}
+
+int direct_fwu_client::read_stream(uint32_t handle, uint8_t *buf, size_t buf_size, size_t *read_len,
+ size_t *total_len)
+{
+ int status = update_agent_read_stream(m_update_agent, handle, m_read_buf, READ_BUF_SIZE,
+ read_len, total_len);
+
+ if (!status && buf && buf_size) {
+ size_t copy_len = (*read_len <= buf_size) ? *read_len : buf_size;
+
+ memcpy(buf, m_read_buf, copy_len);
+ }
+
+ return status;
+}
diff --git a/components/service/fwu/test/fwu_client/direct/direct_fwu_client.h b/components/service/fwu/test/fwu_client/direct/direct_fwu_client.h
new file mode 100644
index 000000000..bfa925b48
--- /dev/null
+++ b/components/service/fwu/test/fwu_client/direct/direct_fwu_client.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DIRECT_FWU_CLIENT_H
+#define DIRECT_FWU_CLIENT_H
+
+#include "service/fwu/test/fwu_client/fwu_client.h"
+
+/* Public interface dependencies */
+struct update_agent;
+
+/*
+ * An fwu_client that interfaces directly with an update_agent. Can be
+ * used for component level testing where tests and update_agent are
+ * combined in the same build.
+ */
+class direct_fwu_client : public fwu_client {
+public:
+ explicit direct_fwu_client(struct update_agent *update_agent);
+ ~direct_fwu_client();
+
+ int begin_staging(void);
+
+ int end_staging(void);
+
+ int cancel_staging(void);
+
+ int accept(const struct uuid_octets *image_type_uuid);
+
+ int select_previous(void);
+
+ int open(const struct uuid_octets *uuid, uint32_t *handle);
+
+ int commit(uint32_t handle, bool accepted);
+
+ int write_stream(uint32_t handle, const uint8_t *data, size_t data_len);
+
+ int read_stream(uint32_t handle, uint8_t *buf, size_t buf_size, size_t *read_len,
+ size_t *total_len);
+
+private:
+ static const size_t READ_BUF_SIZE = 512;
+
+ struct update_agent *m_update_agent;
+ uint8_t m_read_buf[READ_BUF_SIZE];
+};
+
+#endif /* DIRECT_FWU_CLIENT_H */
diff --git a/components/service/fwu/test/fwu_client/fwu_client.h b/components/service/fwu/test/fwu_client/fwu_client.h
new file mode 100644
index 000000000..55f4c873d
--- /dev/null
+++ b/components/service/fwu/test/fwu_client/fwu_client.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_CLIENT_H
+#define FWU_CLIENT_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "common/uuid/uuid.h"
+
+/*
+ * Presents a client interface for interacting with a fwu service provider.
+ * Test cases that use this interface can potentially be reused with alternative
+ * service provider deployments.
+ */
+class fwu_client {
+public:
+ fwu_client()
+ {
+ }
+
+ virtual ~fwu_client()
+ {
+ }
+
+ virtual int begin_staging(void) = 0;
+
+ virtual int end_staging(void) = 0;
+
+ virtual int cancel_staging(void) = 0;
+
+ virtual int accept(const struct uuid_octets *image_type_uuid) = 0;
+
+ virtual int select_previous(void) = 0;
+
+ virtual int open(const struct uuid_octets *uuid, uint32_t *handle) = 0;
+
+ virtual int commit(uint32_t handle, bool accepted) = 0;
+
+ virtual int write_stream(uint32_t handle, const uint8_t *data, size_t data_len) = 0;
+
+ virtual int read_stream(uint32_t handle, uint8_t *buf, size_t buf_size, size_t *read_len,
+ size_t *total_len) = 0;
+};
+
+#endif /* FWU_CLIENT_H */
diff --git a/components/service/fwu/test/fwu_client/remote/component.cmake b/components/service/fwu/test/fwu_client/remote/component.cmake
new file mode 100644
index 000000000..8f3efbbb3
--- /dev/null
+++ b/components/service/fwu/test/fwu_client/remote/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/remote_fwu_client.cpp"
+ )
diff --git a/components/service/fwu/test/fwu_client/remote/remote_fwu_client.cpp b/components/service/fwu/test/fwu_client/remote/remote_fwu_client.cpp
new file mode 100644
index 000000000..803dfe608
--- /dev/null
+++ b/components/service/fwu/test/fwu_client/remote/remote_fwu_client.cpp
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "remote_fwu_client.h"
+
+#include <cassert>
+#include <climits>
+#include <cstring>
+
+#include "protocols/rpc/common/packed-c/encoding.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+#include "protocols/service/fwu/packed-c/opcodes.h"
+#include "protocols/service/fwu/packed-c/status.h"
+
+remote_fwu_client::remote_fwu_client()
+ : fwu_client()
+ , m_client()
+ , m_rpc_session(NULL)
+ , m_service_context(NULL)
+{
+ open_session();
+}
+
+remote_fwu_client::~remote_fwu_client()
+{
+ close_session();
+}
+
+void remote_fwu_client::open_session(void)
+{
+ m_rpc_session = NULL;
+ m_service_context = NULL;
+
+ service_locator_init();
+
+ m_service_context = service_locator_query("sn:trustedfirmware.org:fwu:0");
+
+ if (m_service_context) {
+ m_rpc_session =
+ service_context_open(m_service_context);
+
+ if (m_rpc_session) {
+ service_client_init(&m_client, m_rpc_session);
+
+ } else {
+ service_context_relinquish(m_service_context);
+ m_service_context = NULL;
+ }
+ }
+}
+
+void remote_fwu_client::close_session(void)
+{
+ if (m_service_context) {
+ service_client_deinit(&m_client);
+
+ if (m_rpc_session) {
+ service_context_close(m_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
+
+ service_context_relinquish(m_service_context);
+ m_service_context = NULL;
+ }
+}
+
+int remote_fwu_client::invoke_no_param(unsigned int opcode)
+{
+ int fwu_status = FWU_STATUS_NOT_AVAILABLE;
+ size_t req_len = 0;
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ if (!m_service_context)
+ return fwu_status;
+
+ call_handle = rpc_caller_session_begin(m_rpc_session, &req_buf, req_len, 0);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ m_client.rpc_status = rpc_caller_session_invoke(call_handle, opcode,
+ &resp_buf, &resp_len, &service_status);
+
+ if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED)
+ fwu_status = service_status;
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return fwu_status;
+}
+
+int remote_fwu_client::begin_staging(void)
+{
+ return invoke_no_param(TS_FWU_OPCODE_BEGIN_STAGING);
+}
+
+int remote_fwu_client::end_staging(void)
+{
+ return invoke_no_param(TS_FWU_OPCODE_END_STAGING);
+}
+
+int remote_fwu_client::cancel_staging(void)
+{
+ return invoke_no_param(TS_FWU_OPCODE_CANCEL_STAGING);
+}
+
+int remote_fwu_client::accept(const struct uuid_octets *image_type_uuid)
+{
+ int fwu_status = FWU_STATUS_NOT_AVAILABLE;
+ struct ts_fwu_accept_image_in req_msg = { 0 };
+ size_t req_len = sizeof(struct ts_fwu_accept_image_in);
+
+ if (!m_service_context)
+ return fwu_status;
+
+ memcpy(req_msg.image_type_uuid, image_type_uuid->octets, OSF_UUID_OCTET_LEN);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(m_rpc_session, &req_buf, req_len, 0);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ memcpy(req_buf, &req_msg, req_len);
+
+ m_client.rpc_status = rpc_caller_session_invoke(call_handle,
+ TS_FWU_OPCODE_ACCEPT_IMAGE,
+ &resp_buf, &resp_len, &service_status);
+
+ if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED)
+ fwu_status = service_status;
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return fwu_status;
+}
+
+int remote_fwu_client::select_previous(void)
+{
+ return invoke_no_param(TS_FWU_OPCODE_SELECT_PREVIOUS);
+}
+
+int remote_fwu_client::open(const struct uuid_octets *uuid, uint32_t *handle)
+{
+ int fwu_status = FWU_STATUS_NOT_AVAILABLE;
+ struct ts_fwu_open_in req_msg = { 0 };
+ size_t req_len = sizeof(struct ts_fwu_open_in);
+
+ if (!m_service_context)
+ return fwu_status;
+
+ memcpy(req_msg.image_type_uuid, uuid->octets, OSF_UUID_OCTET_LEN);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(m_rpc_session, &req_buf, req_len,
+ sizeof(struct ts_fwu_open_out));
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ memcpy(req_buf, &req_msg, req_len);
+
+ m_client.rpc_status = rpc_caller_session_invoke(call_handle,
+ TS_FWU_OPCODE_OPEN, &resp_buf,
+ &resp_len, &service_status);
+
+ if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ fwu_status = service_status;
+
+ if ((fwu_status == FWU_STATUS_SUCCESS) &&
+ (resp_len >= sizeof(struct ts_fwu_open_out))) {
+ struct ts_fwu_open_out resp_msg;
+
+ memcpy(&resp_msg, resp_buf, sizeof(struct ts_fwu_open_out));
+ *handle = resp_msg.handle;
+ }
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return fwu_status;
+}
+
+int remote_fwu_client::commit(uint32_t handle, bool accepted)
+{
+ int fwu_status = FWU_STATUS_NOT_AVAILABLE;
+ struct ts_fwu_commit_in req_msg = { 0 };
+ size_t req_len = sizeof(struct ts_fwu_commit_in);
+
+ if (!m_service_context)
+ return fwu_status;
+
+ req_msg.handle = handle;
+ req_msg.acceptance_req = (accepted) ? 0 : 1;
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(m_rpc_session, &req_buf, req_len, 0);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ memcpy(req_buf, &req_msg, req_len);
+
+ m_client.rpc_status = rpc_caller_session_invoke(call_handle,
+ TS_FWU_OPCODE_COMMIT, &resp_buf,
+ &resp_len, &service_status);
+
+ if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED)
+ fwu_status = service_status;
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return fwu_status;
+}
+
+int remote_fwu_client::write_stream(uint32_t handle, const uint8_t *data, size_t data_len)
+{
+ size_t proto_overhead = offsetof(ts_fwu_write_stream_in, payload);
+ size_t max_payload = (m_client.service_info.max_payload > proto_overhead) ?
+ m_client.service_info.max_payload - proto_overhead :
+ 0;
+
+ if (!data || (data_len > (SIZE_MAX - proto_overhead)))
+ return FWU_STATUS_OUT_OF_BOUNDS;
+
+ if (!m_service_context)
+ return FWU_STATUS_NOT_AVAILABLE;
+
+ if (!max_payload)
+ return FWU_STATUS_NOT_AVAILABLE;
+
+ size_t total_written = 0;
+ struct ts_fwu_write_stream_in req_msg;
+
+ req_msg.handle = handle;
+
+ while (total_written < data_len) {
+ size_t bytes_remaining = data_len - total_written;
+ size_t write_len = (bytes_remaining < max_payload) ? bytes_remaining : max_payload;
+ size_t req_len = proto_overhead + write_len;
+
+ req_msg.data_len = write_len;
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(m_rpc_session, &req_buf, req_len, 0);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ memcpy(req_buf, &req_msg, proto_overhead);
+ memcpy(&req_buf[proto_overhead], &data[total_written], write_len);
+
+ total_written += write_len;
+
+ m_client.rpc_status = rpc_caller_session_invoke(call_handle,
+ TS_FWU_OPCODE_WRITE_STREAM,
+ &resp_buf, &resp_len, &service_status);
+
+ rpc_caller_session_end(call_handle);
+
+ if (m_client.rpc_status != TS_RPC_CALL_ACCEPTED)
+ return FWU_STATUS_NOT_AVAILABLE;
+
+ if (service_status != FWU_STATUS_SUCCESS)
+ return (int)service_status;
+
+ } else
+ return FWU_STATUS_NOT_AVAILABLE;
+ }
+
+ return FWU_STATUS_SUCCESS;
+}
+
+int remote_fwu_client::read_stream(uint32_t handle, uint8_t *buf, size_t buf_size, size_t *read_len,
+ size_t *total_len)
+{
+ int fwu_status = FWU_STATUS_NOT_AVAILABLE;
+ struct ts_fwu_read_stream_in req_msg;
+ size_t req_len = sizeof(struct ts_fwu_read_stream_in);
+
+ if (!m_service_context)
+ return fwu_status;
+
+ req_msg.handle = handle;
+
+ *read_len = 0;
+ *total_len = 0;
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(m_rpc_session, &req_buf, req_len,
+ sizeof(struct ts_fwu_read_stream_out) + buf_size);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ memcpy(req_buf, &req_msg, req_len);
+
+ m_client.rpc_status = rpc_caller_session_invoke(call_handle,
+ TS_FWU_OPCODE_READ_STREAM,
+ &resp_buf, &resp_len, &service_status);
+
+ size_t proto_overhead = offsetof(ts_fwu_read_stream_out, payload);
+
+ if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
+ fwu_status = service_status;
+
+ if ((fwu_status == FWU_STATUS_SUCCESS) && (resp_len >= proto_overhead)) {
+ const struct ts_fwu_read_stream_out *resp_msg =
+ (const struct ts_fwu_read_stream_out *)resp_buf;
+
+ *read_len = resp_msg->read_bytes;
+ *total_len = resp_msg->total_bytes;
+
+ if (buf && buf_size) {
+ size_t copy_len = (resp_msg->read_bytes <= buf_size) ?
+ resp_msg->read_bytes :
+ buf_size;
+
+ memcpy(buf, resp_msg->payload, copy_len);
+ }
+ }
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return fwu_status;
+}
diff --git a/components/service/fwu/test/fwu_client/remote/remote_fwu_client.h b/components/service/fwu/test/fwu_client/remote/remote_fwu_client.h
new file mode 100644
index 000000000..ce0511c4c
--- /dev/null
+++ b/components/service/fwu/test/fwu_client/remote/remote_fwu_client.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef REMOTE_FWU_CLIENT_H
+#define REMOTE_FWU_CLIENT_H
+
+#include "service/common/client/service_client.h"
+#include "service/fwu/test/fwu_client/fwu_client.h"
+#include "service_locator.h"
+
+/*
+ * An fwu_client that calls a remote fwu service provider via a
+ * deployment specific RPC caller. Assumes that call request and
+ * response parameters are serialized in-line with the FWU-A specification.
+ */
+class remote_fwu_client : public fwu_client {
+public:
+ remote_fwu_client();
+ ~remote_fwu_client();
+
+ int begin_staging(void);
+
+ int end_staging(void);
+
+ int cancel_staging(void);
+
+ int accept(const struct uuid_octets *image_type_uuid);
+
+ int select_previous(void);
+
+ int open(const struct uuid_octets *uuid, uint32_t *handle);
+
+ int commit(uint32_t handle, bool accepted);
+
+ int write_stream(uint32_t handle, const uint8_t *data, size_t data_len);
+
+ int read_stream(uint32_t handle, uint8_t *buf, size_t buf_size, size_t *read_len,
+ size_t *total_len);
+
+private:
+ int invoke_no_param(unsigned int opcode);
+ void open_session(void);
+ void close_session(void);
+
+ struct service_client m_client;
+ struct rpc_caller_session *m_rpc_session;
+ struct service_context *m_service_context;
+};
+
+#endif /* REMOTE_FWU_CLIENT_H */
diff --git a/components/rpc/common/demux/component.cmake b/components/service/fwu/test/fwu_dut/component.cmake
index a02eefc3e..3dcf12e7b 100644
--- a/components/rpc/common/demux/component.cmake
+++ b/components/service/fwu/test/fwu_dut/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,5 +9,5 @@ if (NOT DEFINED TGT)
endif()
target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/rpc_demux.c"
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_dut.cpp"
)
diff --git a/components/service/fwu/test/fwu_dut/fwu_dut.cpp b/components/service/fwu/test/fwu_dut/fwu_dut.cpp
new file mode 100644
index 000000000..0e6f15f0e
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut/fwu_dut.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fwu_dut.h"
+
+#include <CppUTest/TestHarness.h>
+#include <cassert>
+#include <cstring>
+#include <string>
+
+#include "common/endian/le.h"
+#include "service/fwu/test/metadata_checker/metadata_checker_v1.h"
+#include "service/fwu/test/metadata_checker/metadata_checker_v2.h"
+
+const char *fwu_dut::VALID_IMAGE_HEADER = "Valid-fw-image-";
+
+fwu_dut::fwu_dut()
+ : m_generated_image_count(0)
+ , m_metadata_version(1)
+{
+}
+
+fwu_dut::fwu_dut(unsigned int metadata_version)
+ : m_generated_image_count(0)
+ , m_metadata_version(metadata_version)
+{
+}
+
+fwu_dut::~fwu_dut()
+{
+}
+
+void fwu_dut::generate_image_data(std::vector<uint8_t> *image_data, size_t image_size)
+{
+ std::string fixed_header(VALID_IMAGE_HEADER);
+
+ /* Image header consists of:
+ * - Fixed header
+ * - Image size (32-bit)
+ * - Sequence count (32-bit)
+ */
+ size_t header_len = fixed_header.size() + sizeof(uint32_t) + sizeof(uint32_t);
+
+ /* Reserve space */
+ image_data->resize(image_size);
+
+ if (image_size >= header_len) {
+ /* Prepare image header */
+ memcpy(image_data->data(), fixed_header.data(), fixed_header.size());
+
+ store_u32_le(image_data->data(), fixed_header.size(),
+ static_cast<uint32_t>(image_size));
+
+ store_u32_le(image_data->data(), fixed_header.size() + sizeof(uint32_t),
+ static_cast<uint32_t>(m_generated_image_count));
+
+ /* Fill any remaining space */
+ if (image_size > header_len) {
+ uint8_t fill_val = static_cast<uint8_t>(m_generated_image_count);
+ size_t fill_len = image_size - header_len;
+
+ memset(image_data->data() + header_len, fill_val, fill_len);
+ }
+ } else if (image_size > 0) {
+ /* No room for header so just initialise to fixed value. This will
+ * fail any image verification check.
+ */
+ memset(image_data->data(), 0, image_size);
+ }
+
+ ++m_generated_image_count;
+}
+
+void fwu_dut::whole_volume_image_type_uuid(unsigned int location_index,
+ struct uuid_octets *uuid) const
+{
+ static const char *img_type_guid[] = { "cb0faf2f-f498-49fb-9810-cb09dac1184f",
+ "e9755079-db61-4d90-8a8a-45727eaa1c6e",
+ "d439bc29-83e6-40c7-babe-eb59e415c05e",
+ "433a6c93-8bb0-4966-b49c-dc0c56080d19" };
+
+ CHECK_TRUE(location_index < sizeof(img_type_guid) / sizeof(char *));
+
+ uuid_guid_octets_from_canonical(uuid, img_type_guid[location_index]);
+}
+
+metadata_checker *fwu_dut::create_metadata_checker(metadata_fetcher *metadata_fetcher,
+ unsigned int num_images) const
+{
+ if (m_metadata_version == 1)
+ return new metadata_checker_v1(metadata_fetcher, num_images);
+
+ if (m_metadata_version == 2)
+ return new metadata_checker_v2(metadata_fetcher, num_images);
+
+ /* Unsupported metadata version */
+ assert(false);
+
+ return NULL;
+}
+
+unsigned int fwu_dut::metadata_version(void) const
+{
+ return m_metadata_version;
+}
diff --git a/components/service/fwu/test/fwu_dut/fwu_dut.h b/components/service/fwu/test/fwu_dut/fwu_dut.h
new file mode 100644
index 000000000..27b27d77e
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut/fwu_dut.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_DUT_H
+#define FWU_DUT_H
+
+#include <vector>
+
+#include "common/uuid/uuid.h"
+#include "service/fwu/agent/fw_directory.h"
+#include "service/fwu/test/fwu_client/fwu_client.h"
+#include "service/fwu/test/metadata_checker/metadata_checker.h"
+
+/*
+ * An fwu_dut represents a device-under-test for the purpose of testing
+ * firmware update functionality. The fwu_dut presents a common interface
+ * that decouples test cases from details of the concrete device under test.
+ */
+class fwu_dut {
+public:
+ fwu_dut();
+ fwu_dut(unsigned int metadata_version);
+ virtual ~fwu_dut();
+
+ /**
+ * \brief Simulates a boot of the DUT.
+ *
+ * Mimics boot loader FWU metadata usage and performs a simple verification
+ * of fw images installed in the bank corresponding to the selected boot
+ * index. Initializes the update_agent in the same way as with a real
+ * deployment.
+ *
+ * \param[in] from_active_bank Where to boot from
+ */
+ virtual void boot(bool from_active_bank = true) = 0;
+
+ /**
+ * \brief Simulates a shutdown of the DUT
+ *
+ * The update_agent is de-initialized but image and metadata storage is
+ * left alone. Simulates a physical device shutdown.
+ */
+ virtual void shutdown(void) = 0;
+
+ /**
+ * \brief Returns boot info seen by the boot loader
+ *
+ * \return A boot_info structure
+ */
+ virtual struct boot_info get_boot_info(void) const = 0;
+
+ /**
+ * \brief Factory method to construct a metadata_checker
+ *
+ * To decouple test code from different versions of FWU metadata, the
+ * metadata_checker class can be used to provide a neutral interface.
+ * This method creates a concrete metadata_checker that is compatible
+ * with the version generated by the DUT. The caller is responsible for
+ * destroying the metadata_checker using delete.
+ *
+ * \param[in] is_primary True to use the primary, false the backup copy
+ *
+ * \return The constructed metadata_checker
+ */
+ virtual metadata_checker *create_metadata_checker(bool is_primary = true) const = 0;
+
+ /**
+ * \brief Factory method to construct a fwu_client
+ *
+ * Constructs a fwu_client to provide an interface for interacting with
+ * the fwu service provider associated with the DUT. The caller is
+ * responsible for destroying the fwu_client using delete.
+ *
+ * \return The constructed fwu_client
+ */
+ virtual fwu_client *create_fwu_client(void) = 0;
+
+ /**
+ * \brief Generate fw image data
+ *
+ * Generates a fake image that can be checked during dut boot for
+ * validity. Use to provide image data for update testing
+ *
+ * \param[in] image_data Image data written to the provided vector
+ * \param[in] image_size The required image size
+ */
+ void generate_image_data(std::vector<uint8_t> *image_data, size_t image_size = 4096);
+
+ /**
+ * \brief Returns image type UUIDs
+ *
+ * Image type UUIDS for updatable whole volume images. Assumes
+ * one whole volume image type per location.
+ *
+ * \param[in] location_index 0..num_locations-1
+ * \param[out] uuid Outputs the GUID octets
+ */
+ virtual void whole_volume_image_type_uuid(unsigned int location_index,
+ struct uuid_octets *uuid) const;
+
+protected:
+ /**
+ * \brief Create a metadata_checker for the configured metadata version
+ *
+ * Creates a metadata_checker using 'new' that is compatible with the metadata
+ * version specified for the DUT on construction. Uses the provided metadata_fetcher
+ * to fetch the metadata prior to checking.
+ *
+ * \param[in] metadata_fetcher To fetch the metadata
+ * \param[in] num_images The expected number of images
+ */
+ metadata_checker *create_metadata_checker(metadata_fetcher *metadata_fetcher,
+ unsigned int num_images) const;
+
+ /**
+ * \brief Returns the configured FWU metadata version
+ *
+ * In a real system, the bootloader will advertise the metadata version that it
+ * understands.
+ *
+ * \return Metadata version
+ */
+ unsigned int metadata_version(void) const;
+
+ static const char *VALID_IMAGE_HEADER;
+
+private:
+ unsigned int m_generated_image_count;
+ unsigned int m_metadata_version;
+};
+
+#endif /* FWU_DUT_H */
diff --git a/components/service/fwu/test/fwu_dut/proxy/component.cmake b/components/service/fwu/test/fwu_dut/proxy/component.cmake
new file mode 100644
index 000000000..c10a4be3b
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut/proxy/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/proxy_fwu_dut.cpp"
+ )
diff --git a/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.cpp b/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.cpp
new file mode 100644
index 000000000..a736bf772
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "proxy_fwu_dut.h"
+
+#include <cassert>
+
+#include "service/fwu/test/fwu_client/remote/remote_fwu_client.h"
+#include "service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.h"
+
+proxy_fwu_dut::proxy_fwu_dut(unsigned int num_locations, unsigned int metadata_version,
+ fwu_dut *remote_dut)
+ : fwu_dut(metadata_version)
+ , m_num_locations(num_locations)
+ , m_remote_dut(remote_dut)
+{
+}
+
+proxy_fwu_dut::~proxy_fwu_dut()
+{
+ delete m_remote_dut;
+ m_remote_dut = NULL;
+}
+
+void proxy_fwu_dut::boot(bool from_active_bank)
+{
+ if (m_remote_dut)
+ m_remote_dut->boot(from_active_bank);
+}
+
+void proxy_fwu_dut::shutdown(void)
+{
+ if (m_remote_dut)
+ m_remote_dut->shutdown();
+}
+
+struct boot_info proxy_fwu_dut::get_boot_info(void) const
+{
+ assert(m_remote_dut);
+ return m_remote_dut->get_boot_info();
+}
+
+metadata_checker *proxy_fwu_dut::create_metadata_checker(bool is_primary) const
+{
+ (void)is_primary;
+
+ /* Use service interface to fetch metadata as volume access is no possible */
+ fwu_client *fwu_client = new remote_fwu_client;
+ metadata_fetcher *metadata_fetcher = new client_metadata_fetcher(fwu_client);
+
+ return fwu_dut::create_metadata_checker(metadata_fetcher, m_num_locations);
+}
+
+fwu_client *proxy_fwu_dut::create_fwu_client(void)
+{
+ /* Access service via RPC */
+ return new remote_fwu_client;
+}
diff --git a/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h b/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h
new file mode 100644
index 000000000..d334fe972
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PROXY_FWU_DUT_H
+#define PROXY_FWU_DUT_H
+
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+
+/*
+ * A proxy_fwu_dut is an fwu_dut that acts as a proxy for a full fwu_dut
+ * with access to updatable firmware. The proxy_fwu_dut is used in test
+ * integrations where the fwu service is being accessed via RPC e.g. from
+ * Nwd.
+ */
+class proxy_fwu_dut : public fwu_dut {
+public:
+ /**
+ * \brief proxy_fwu_dut constructor
+ *
+ * \param[in] num_locations The number of updatable fw locations
+ * \param[in] metadata_version FWU metadata version supported by bootloader
+ * \param[in] remote_dut The associated remote fwu dut
+ */
+ proxy_fwu_dut(unsigned int num_locations, unsigned int metadata_version,
+ fwu_dut *remote_dut);
+
+ ~proxy_fwu_dut();
+
+ void boot(bool from_active_bank);
+ void shutdown(void);
+
+ struct boot_info get_boot_info(void) const;
+
+ metadata_checker *create_metadata_checker(bool is_primary) const;
+ fwu_client *create_fwu_client(void);
+
+private:
+ unsigned int m_num_locations;
+ fwu_dut *m_remote_dut;
+};
+
+#endif /* PROXY_FWU_DUT_H */
diff --git a/components/service/fwu/test/fwu_dut/sim/component.cmake b/components/service/fwu/test/fwu_dut/sim/component.cmake
new file mode 100644
index 000000000..cb66728fe
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut/sim/component.cmake
@@ -0,0 +1,22 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/sim_fwu_dut.cpp"
+ )
+
+#-------------------------------------------------------------------------------
+# Override TF-A defaults to increase number of io devices to accommodate
+# the needs of the sim_fwu_dut.
+#-------------------------------------------------------------------------------
+target_compile_definitions(${TGT} PRIVATE
+MAX_IO_HANDLES=12
+MAX_IO_DEVICES=12
+) \ No newline at end of file
diff --git a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
new file mode 100644
index 000000000..5415cc7d1
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "sim_fwu_dut.h"
+
+#include <CppUTest/TestHarness.h>
+#include <cassert>
+#include <cstring>
+#include <sstream>
+
+#include "common/endian/le.h"
+#include "media/disk/guid.h"
+#include "media/volume/index/volume_index.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h"
+#include "service/fwu/fw_store/banked/volume_id.h"
+#include "service/fwu/inspector/direct/direct_fw_inspector.h"
+#include "service/fwu/installer/installer_index.h"
+#include "service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h"
+#include "service/fwu/test/fwu_client/direct/direct_fwu_client.h"
+#include "service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.h"
+
+sim_fwu_dut::sim_fwu_dut(unsigned int num_locations, unsigned int metadata_version,
+ bool allow_partial_updates)
+ : fwu_dut(metadata_version)
+ , m_is_booted(false)
+ , m_is_first_boot(true)
+ , m_boot_info()
+ , m_metadata_checker(NULL)
+ , m_num_locations(num_locations)
+ , m_service_iface(NULL)
+ , m_fw_flash()
+ , m_partitioned_block_store()
+ , m_block_store(NULL)
+ , m_fw_volume_used_count(0)
+ , m_fw_volume_pool()
+ , m_raw_installer_used_count(0)
+ , m_raw_installer_pool()
+ , m_copy_installer_used_count(0)
+ , m_copy_installer_pool()
+ , m_update_agent()
+ , m_fw_store()
+ , m_fwu_provider()
+{
+ volume_index_init();
+ installer_index_init();
+
+ construct_storage(num_locations);
+ construct_fw_volumes(num_locations);
+ construct_installers(num_locations, allow_partial_updates);
+
+ install_factory_images(num_locations);
+
+ /* Initialise fwu service provider prior to boot to ensure that a
+ * viable service interface exists to safely handle an incoming
+ * request that occurs prior to the boot method being called.
+ * Note that the update_agent is in the de-initialized state so
+ * any operations will be denied.
+ */
+ memset(&m_update_agent, 0, sizeof(m_update_agent));
+ m_update_agent.state = FWU_STATE_DEINITIALZED;
+
+ m_service_iface = fwu_provider_init(&m_fwu_provider, &m_update_agent);
+
+ fwu_provider_register_serializer(&m_fwu_provider, TS_RPC_ENCODING_PACKED_C,
+ packedc_fwu_provider_serializer_instance());
+
+ m_metadata_checker = create_metadata_checker();
+}
+
+sim_fwu_dut::~sim_fwu_dut()
+{
+ shutdown();
+
+ delete m_metadata_checker;
+ m_metadata_checker = NULL;
+
+ fwu_provider_deinit(&m_fwu_provider);
+
+ destroy_installers();
+ destroy_fw_volumes();
+ destroy_storage();
+
+ installer_index_clear();
+ volume_index_clear();
+}
+
+void sim_fwu_dut::boot(bool from_active_bank)
+{
+ if (m_is_booted)
+ return;
+
+ if (m_is_first_boot) {
+ /* First boot where valid FWU metadata does not yet exist. */
+ m_boot_info.boot_index = m_boot_info.active_index =
+ m_boot_info.previous_active_index = FIRST_BOOT_BANK_INDEX;
+ m_is_first_boot = false;
+
+ } else {
+ /* On subsequent boots, mimic the boot loader and derive boot
+ * info from the FWU metadata.
+ */
+ m_metadata_checker->get_active_indices(&m_boot_info.active_index,
+ &m_boot_info.previous_active_index);
+
+ m_boot_info.boot_index = (from_active_bank) ? m_boot_info.active_index :
+ m_boot_info.previous_active_index;
+ }
+
+ /* Now mimic boot loader image verification */
+ verify_boot_images(m_boot_info.boot_index);
+
+ /* Performs the generic update agent initialization that occurs on
+ * each system boot.
+ */
+ int status = banked_fw_store_init(&m_fw_store, select_metadata_serializer());
+ LONGS_EQUAL(0, status);
+
+ status = update_agent_init(&m_update_agent, m_boot_info.boot_index,
+ direct_fw_inspector_inspect, &m_fw_store);
+ LONGS_EQUAL(0, status);
+
+ m_is_booted = true;
+}
+
+void sim_fwu_dut::shutdown(void)
+{
+ if (!m_is_booted)
+ return;
+
+ /* Ensure all install streams are closed */
+ update_agent_cancel_staging(&m_update_agent);
+
+ update_agent_deinit(&m_update_agent);
+ banked_fw_store_deinit(&m_fw_store);
+
+ m_is_booted = false;
+}
+
+struct rpc_service_interface *sim_fwu_dut::get_service_interface(void)
+{
+ return m_service_iface;
+}
+
+struct boot_info sim_fwu_dut::get_boot_info(void) const
+{
+ return m_boot_info;
+}
+
+metadata_checker *sim_fwu_dut::create_metadata_checker(bool is_primary) const
+{
+ struct uuid_octets partition_guid;
+
+ fwu_metadata_partition_guid(is_primary, &partition_guid);
+
+ metadata_fetcher *metadata_fetcher =
+ new volume_metadata_fetcher(&partition_guid, m_block_store);
+
+ return fwu_dut::create_metadata_checker(metadata_fetcher, m_num_locations);
+}
+
+fwu_client *sim_fwu_dut::create_fwu_client(void)
+{
+ return new direct_fwu_client(&m_update_agent);
+}
+
+void sim_fwu_dut::fw_partition_guid(unsigned int location_index, unsigned int bank_index,
+ struct uuid_octets *uuid) const
+{
+ static const char *partition_guid[MAX_LOCATIONS][BANK_SCHEME_NUM_BANKS] = {
+ { "318757ec-82a0-48ce-a0d9-dfdeee6847a9", "3455a361-4074-42a3-ac0f-0e217c58494a" },
+ { "5feb0dff-3d4b-42ab-9635-c112cf641f2b", "d75c1efc-6c8c-458a-aa72-41810d1d8a99" },
+ { "0558ce63-db89-40ad-8039-1fafeb057fc8", "f07f1be5-077d-487f-9bd9-1ae33ed580e9" },
+ { "3b00979c-e776-4e79-b675-f78681b4cce3", "3de167ca-5e8c-4f05-9f87-e0c6a57538a5" }
+ };
+
+ CHECK_TRUE(location_index < MAX_LOCATIONS);
+ CHECK_TRUE(bank_index < BANK_SCHEME_NUM_BANKS);
+
+ uuid_guid_octets_from_canonical(uuid, partition_guid[location_index][bank_index]);
+}
+
+void sim_fwu_dut::fwu_metadata_partition_guid(bool is_primary, struct uuid_octets *uuid) const
+{
+ if (is_primary)
+ uuid_guid_octets_from_canonical(uuid,
+ DISK_GUID_UNIQUE_PARTITION_PRIMARY_FWU_METADATA);
+ else
+ uuid_guid_octets_from_canonical(uuid,
+ DISK_GUID_UNIQUE_PARTITION_BACKUP_FWU_METADATA);
+}
+
+void sim_fwu_dut::disk_guid(struct uuid_octets *uuid) const
+{
+ uuid_guid_octets_from_canonical(uuid, "da92a93d-91d3-4b74-9102-7b45c21fe7db");
+}
+
+void sim_fwu_dut::construct_storage(unsigned int num_locations)
+{
+ size_t required_storage_blocks =
+ METADATA_VOLUME_NUM_BLOCKS * 2 +
+ FW_VOLUME_NUM_BLOCKS * BANK_SCHEME_NUM_BANKS * num_locations;
+
+ struct uuid_octets flash_store_guid;
+
+ disk_guid(&flash_store_guid);
+
+ /* Construct the 'flash' */
+ struct block_store *flash_store = ram_block_store_init(
+ &m_fw_flash, &flash_store_guid, required_storage_blocks, FLASH_BLOCK_SIZE);
+
+ /* Stack a partitioned_block_store over the flash */
+ m_block_store = partitioned_block_store_init(&m_partitioned_block_store, 0,
+ &flash_store_guid, flash_store, NULL);
+
+ /* Add all disk partitions */
+ unsigned int lba = 0;
+ struct uuid_octets partition_guid;
+
+ /* First the primary fwu metadata partition */
+ fwu_metadata_partition_guid(true, &partition_guid);
+ bool is_added = partitioned_block_store_add_partition(&m_partitioned_block_store,
+ &partition_guid, lba,
+ lba + METADATA_VOLUME_NUM_BLOCKS - 1,
+ 0, NULL);
+
+ CHECK_TRUE(is_added);
+ lba += METADATA_VOLUME_NUM_BLOCKS;
+
+ /* Add partitions for each fw location */
+ for (unsigned int location = 0; location < num_locations; location++) {
+ for (unsigned int bank = 0; bank < BANK_SCHEME_NUM_BANKS; bank++) {
+ fw_partition_guid(location, bank, &partition_guid);
+ is_added = partitioned_block_store_add_partition(
+ &m_partitioned_block_store, &partition_guid, lba,
+ lba + FW_VOLUME_NUM_BLOCKS - 1, 0, NULL);
+
+ CHECK_TRUE(is_added);
+ lba += FW_VOLUME_NUM_BLOCKS;
+ }
+ }
+
+ /* Finally, add the backup fwu metadata partition */
+ fwu_metadata_partition_guid(false, &partition_guid);
+ is_added = partitioned_block_store_add_partition(&m_partitioned_block_store,
+ &partition_guid, lba,
+ lba + METADATA_VOLUME_NUM_BLOCKS - 1, 0,
+ NULL);
+
+ CHECK_TRUE(is_added);
+}
+
+void sim_fwu_dut::destroy_storage(void)
+{
+ partitioned_block_store_deinit(&m_partitioned_block_store);
+ ram_block_store_deinit(&m_fw_flash);
+}
+
+void sim_fwu_dut::construct_fw_volumes(unsigned int num_locations)
+{
+ int status = 0;
+ struct volume *volume = NULL;
+ struct uuid_octets partition_guid;
+
+ /* Construct volume for primary fwu metadata access */
+ fwu_metadata_partition_guid(true, &partition_guid);
+
+ status = block_volume_init(&m_fw_volume_pool[m_fw_volume_used_count], m_block_store,
+ &partition_guid, &volume);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(volume);
+
+ status = volume_index_add(BANKED_VOLUME_ID_PRIMARY_METADATA, volume);
+ LONGS_EQUAL(0, status);
+ ++m_fw_volume_used_count;
+
+ /* Construct volume for backup fwu metadata access */
+ fwu_metadata_partition_guid(false, &partition_guid);
+
+ status = block_volume_init(&m_fw_volume_pool[m_fw_volume_used_count], m_block_store,
+ &partition_guid, &volume);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(volume);
+
+ status = volume_index_add(BANKED_VOLUME_ID_BACKUP_METADATA, volume);
+ LONGS_EQUAL(0, status);
+ ++m_fw_volume_used_count;
+
+ /* Construct volumes for each fw storage partition */
+ for (unsigned int location = 0; location < num_locations; location++) {
+ for (unsigned int bank = 0; bank < BANK_SCHEME_NUM_BANKS; bank++) {
+ fw_partition_guid(location, bank, &partition_guid);
+
+ status = block_volume_init(&m_fw_volume_pool[m_fw_volume_used_count],
+ m_block_store, &partition_guid, &volume);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(volume);
+
+ status = volume_index_add(banked_volume_id(location, banked_usage_id(bank)),
+ volume);
+ LONGS_EQUAL(0, status);
+ ++m_fw_volume_used_count;
+ }
+ }
+}
+
+void sim_fwu_dut::destroy_fw_volumes(void)
+{
+ for (unsigned int i = 0; i < m_fw_volume_used_count; i++)
+ block_volume_deinit(&m_fw_volume_pool[i]);
+
+ m_fw_volume_used_count = 0;
+}
+
+void sim_fwu_dut::construct_installers(unsigned int num_locations, bool allow_partial_updates)
+{
+ for (unsigned int location = 0; location < num_locations; location++) {
+ /* Provides a raw and optional copy installer per location. The raw_installer
+ * is used for installing whole volume images using an externally streamed
+ * image while the copy installer is used to copy the previously good whole
+ * volume image to the update bank for cases where an incoming update
+ * did not include images for all locations. Use of a copy_installer to
+ * support this case is optional. By not registering a copy_installer for
+ * a location, an update attempt will fail if and image for the location
+ * was not included in an incoming update package.
+ */
+ struct uuid_octets img_type_uuid;
+
+ whole_volume_image_type_uuid(location, &img_type_uuid);
+
+ struct raw_installer *raw_installer =
+ &m_raw_installer_pool[m_raw_installer_used_count];
+
+ raw_installer_init(raw_installer, &img_type_uuid, location);
+ installer_index_register(&raw_installer->base_installer);
+ ++m_raw_installer_used_count;
+
+ if (allow_partial_updates) {
+ struct copy_installer *copy_installer =
+ &m_copy_installer_pool[m_copy_installer_used_count];
+
+ copy_installer_init(copy_installer, &img_type_uuid, location);
+ installer_index_register(&copy_installer->base_installer);
+ ++m_copy_installer_used_count;
+ }
+ }
+}
+
+void sim_fwu_dut::destroy_installers(void)
+{
+ for (unsigned int i = 0; i < m_raw_installer_used_count; i++)
+ raw_installer_deinit(&m_raw_installer_pool[i]);
+
+ m_raw_installer_used_count = 0;
+
+ for (unsigned int i = 0; i < m_copy_installer_used_count; i++)
+ copy_installer_deinit(&m_copy_installer_pool[i]);
+
+ m_copy_installer_used_count = 0;
+}
+
+void sim_fwu_dut::install_factory_images(unsigned int num_locations)
+{
+ /* Install valid images into bank 0 to mimic the state of
+ * a device with factory programmed flash.
+ */
+ for (unsigned int location = 0; location < num_locations; location++) {
+ struct volume *volume = NULL;
+ size_t len_written = 0;
+
+ int status = volume_index_find(
+ banked_volume_id(location, banked_usage_id(FIRST_BOOT_BANK_INDEX)),
+ &volume);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(volume);
+
+ std::vector<uint8_t> image_data;
+
+ generate_image_data(&image_data);
+
+ status = volume_open(volume);
+ LONGS_EQUAL(0, status);
+
+ status = volume_write(volume, (uintptr_t)image_data.data(), image_data.size(),
+ &len_written);
+ LONGS_EQUAL(0, status);
+ UNSIGNED_LONGS_EQUAL(image_data.size(), len_written);
+
+ status = volume_close(volume);
+ LONGS_EQUAL(0, status);
+ }
+}
+
+void sim_fwu_dut::verify_boot_images(unsigned int boot_index)
+{
+ for (unsigned int location = 0; location < m_num_locations; location++) {
+ struct volume *volume = NULL;
+
+ int status = volume_index_find(
+ banked_volume_id(location, banked_usage_id(boot_index)), &volume);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(volume);
+
+ status = volume_open(volume);
+ LONGS_EQUAL(0, status);
+
+ sim_fwu_dut::verify_image(volume);
+
+ status = volume_close(volume);
+ LONGS_EQUAL(0, status);
+ }
+}
+
+const struct metadata_serializer *sim_fwu_dut::select_metadata_serializer(void) const
+{
+ unsigned int version = metadata_version();
+
+ if (version == 1)
+ return metadata_serializer_v1();
+
+ if (version == 2)
+ return metadata_serializer_v2();
+
+ /* Metadata version not supported */
+ assert(false);
+
+ return NULL;
+}
+
+void sim_fwu_dut::verify_image(struct volume *volume)
+{
+ std::string fixed_header(VALID_IMAGE_HEADER);
+ size_t header_len = fixed_header.size() + sizeof(uint32_t) + sizeof(uint32_t);
+
+ /* Read image header */
+ uint8_t header_buf[header_len];
+ size_t total_bytes_read = 0;
+
+ int status = volume_read(volume, (uintptr_t)header_buf, header_len, &total_bytes_read);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(total_bytes_read == header_len);
+
+ /* Verify header and extract values */
+ MEMCMP_EQUAL(fixed_header.data(), header_buf, fixed_header.size());
+
+ size_t image_size = load_u32_le(header_buf, fixed_header.size());
+ uint32_t seq_num = load_u32_le(header_buf, fixed_header.size() + sizeof(uint32_t));
+
+ CHECK_TRUE(image_size >= header_len);
+
+ /* Read the remainder of the image and check data is as expected */
+ uint8_t expected_fill_val = static_cast<uint8_t>(seq_num);
+
+ while (total_bytes_read < image_size) {
+ uint8_t read_buf[1024];
+ size_t bytes_read = 0;
+ size_t bytes_remaining = image_size - total_bytes_read;
+ size_t bytes_to_read = (bytes_remaining > sizeof(read_buf)) ? sizeof(read_buf) :
+ bytes_remaining;
+
+ status = volume_read(volume, (uintptr_t)read_buf, bytes_to_read, &bytes_read);
+ LONGS_EQUAL(0, status);
+ UNSIGNED_LONGS_EQUAL(bytes_to_read, bytes_read);
+
+ for (size_t i = 0; i < bytes_read; i++)
+ BYTES_EQUAL(expected_fill_val, read_buf[i]);
+
+ total_bytes_read += bytes_read;
+ }
+
+ UNSIGNED_LONGS_EQUAL(image_size, total_bytes_read);
+}
diff --git a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
new file mode 100644
index 000000000..f10d2c533
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SIM_FWU_DUT_H
+#define SIM_FWU_DUT_H
+
+#include <cstddef>
+#include <string>
+
+#include "common/uuid/uuid.h"
+#include "media/volume/block_volume/block_volume.h"
+#include "service/block_storage/block_store/device/ram/ram_block_store.h"
+#include "service/block_storage/block_store/partitioned/partitioned_block_store.h"
+#include "service/fwu/agent/fw_directory.h"
+#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/fw_store/banked/bank_scheme.h"
+#include "service/fwu/fw_store/banked/banked_fw_store.h"
+#include "service/fwu/installer/copy/copy_installer.h"
+#include "service/fwu/installer/raw/raw_installer.h"
+#include "service/fwu/provider/fwu_provider.h"
+#include "service/fwu/test/fwu_client/fwu_client.h"
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/metadata_checker/metadata_checker.h"
+
+/*
+ * An sim_fwu_dut is an aggregate of components that simulates
+ * an updatable device that receives updates via the interface presented
+ * by an fwu_client. A certain amount of construction-time configuration is
+ * supported to allow for testing with alternative firmware store
+ * realizations. As much as possible, the set of components that forms
+ * the DUT is the same as what is used in real deployments.
+ */
+class sim_fwu_dut : public fwu_dut {
+public:
+ /**
+ * \brief sim_fwu_dut constructor
+ *
+ * \param[in] num_locations The number of updatable fw locations
+ * \param[in] metadata_version FWU metadata version supported by bootloader
+ * \param[in] allow_partial_updates True if updating a subset of locations is permitted
+ */
+ sim_fwu_dut(unsigned int num_locations, unsigned int metadata_version,
+ bool allow_partial_updates = false);
+
+ ~sim_fwu_dut();
+
+ void boot(bool from_active_bank = true);
+ void shutdown(void);
+
+ struct boot_info get_boot_info(void) const;
+
+ metadata_checker *create_metadata_checker(bool is_primary = true) const;
+ fwu_client *create_fwu_client(void);
+
+ struct rpc_service_interface *get_service_interface(void);
+
+private:
+ /* Maximum locations supported */
+ static const unsigned int MAX_LOCATIONS = 4;
+
+ /* Volumes needed for fwu metadata access */
+ static const unsigned int FWU_METADATA_VOLUMES = 2;
+
+ /* Boot index on first boot before valid FWU metadata exists */
+ static const unsigned int FIRST_BOOT_BANK_INDEX = 0;
+
+ /* Platform storage configuration */
+ static const size_t FLASH_BLOCK_SIZE = 512;
+ static const size_t FW_VOLUME_NUM_BLOCKS = 20;
+ static const size_t METADATA_VOLUME_NUM_BLOCKS = 4;
+
+ void fw_partition_guid(unsigned int location_index, unsigned int bank_index,
+ struct uuid_octets *uuid) const;
+
+ void fwu_metadata_partition_guid(bool is_primary, struct uuid_octets *uuid) const;
+
+ void disk_guid(struct uuid_octets *uuid) const;
+
+ void construct_storage(unsigned int num_locations);
+ void destroy_storage(void);
+
+ void construct_fw_volumes(unsigned int num_locations);
+ void destroy_fw_volumes(void);
+
+ void construct_installers(unsigned int num_locations, bool allow_partial_updates);
+ void destroy_installers(void);
+
+ void install_factory_images(unsigned int num_locations);
+ void verify_boot_images(unsigned int boot_index);
+
+ static void verify_image(struct volume *volume);
+
+ const struct metadata_serializer *select_metadata_serializer(void) const;
+
+ bool m_is_booted;
+ bool m_is_first_boot;
+ struct boot_info m_boot_info;
+ metadata_checker *m_metadata_checker;
+ unsigned int m_num_locations;
+ struct rpc_service_interface *m_service_iface;
+
+ /* Firmware storage */
+ struct ram_block_store m_fw_flash;
+ struct partitioned_block_store m_partitioned_block_store;
+ struct block_store *m_block_store;
+
+ /* Pools of volume objects */
+ size_t m_fw_volume_used_count;
+ struct block_volume
+ m_fw_volume_pool[MAX_LOCATIONS * BANK_SCHEME_NUM_BANKS + FWU_METADATA_VOLUMES];
+
+ /* Pools of different types of installer */
+ size_t m_raw_installer_used_count;
+ struct raw_installer m_raw_installer_pool[MAX_LOCATIONS];
+ size_t m_copy_installer_used_count;
+ struct copy_installer m_copy_installer_pool[MAX_LOCATIONS];
+
+ /* The core fwu service components */
+ struct update_agent m_update_agent;
+ struct fw_store m_fw_store;
+ struct fwu_provider m_fwu_provider;
+};
+
+#endif /* SIM_FWU_DUT_H */
diff --git a/components/service/fwu/test/fwu_dut_factory/fwu_dut_factory.h b/components/service/fwu/test/fwu_dut_factory/fwu_dut_factory.h
new file mode 100644
index 000000000..3876267b2
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut_factory/fwu_dut_factory.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_DUT_FACTORY_H
+#define FWU_DUT_FACTORY_H
+
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+
+/*
+ * A factory for constructing fwu_dut objects. To allow for different test
+ * configurations, alternative implementations of the factory method are
+ * possible. The fwu_dut_factory provides a common interface to allow test
+ * cases that depend on a fwu_dut to be reused in different deployments.
+ */
+class fwu_dut_factory {
+public:
+ /**
+ * \brief Factory method to construct concrete fwu_dut objects
+ *
+ * \param[in] num_locations The number of updatable fw locations
+ * \param[in] allow_partial_updates True if updating a subset of locations is permitted
+ *
+ * \return The constructed fwu_dut
+ */
+ static fwu_dut *create(unsigned int num_locations, bool allow_partial_updates = false);
+
+private:
+ static const unsigned int FWU_METADATA_VERSION = 2;
+};
+
+#endif /* FWU_DUT_FACTORY_H */
diff --git a/components/service/fwu/test/fwu_dut_factory/remote/component.cmake b/components/service/fwu/test/fwu_dut_factory/remote/component.cmake
new file mode 100644
index 000000000..411d320e4
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut_factory/remote/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_dut_factory.cpp"
+ )
diff --git a/components/service/fwu/test/fwu_dut_factory/remote/fwu_dut_factory.cpp b/components/service/fwu/test/fwu_dut_factory/remote/fwu_dut_factory.cpp
new file mode 100644
index 000000000..16a3ea0aa
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut_factory/remote/fwu_dut_factory.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+
+#include "service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h"
+
+/*
+ * A factory for constructing fwu_dut objects for remote access to
+ * a real fwu_service provider. Because the service provider will have
+ * been configured using its own mechanism, configuration parameters
+ * passed on 'create' are ignored.
+ */
+fwu_dut *fwu_dut_factory::create(unsigned int num_locations, bool allow_partial_updates)
+{
+ /* Determined by FWU service provider configuration */
+ (void)num_locations;
+ (void)allow_partial_updates;
+
+ /* Construct a proxy_fwu_dut with no explicit link to a backend fwu_dut */
+ return new proxy_fwu_dut(num_locations, FWU_METADATA_VERSION, NULL);
+} \ No newline at end of file
diff --git a/components/service/fwu/test/fwu_dut_factory/remote_sim/component.cmake b/components/service/fwu/test/fwu_dut_factory/remote_sim/component.cmake
new file mode 100644
index 000000000..3add66d3b
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut_factory/remote_sim/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_dut_factory.cpp"
+ )
diff --git a/components/service/fwu/test/fwu_dut_factory/remote_sim/fwu_dut_factory.cpp b/components/service/fwu/test/fwu_dut_factory/remote_sim/fwu_dut_factory.cpp
new file mode 100644
index 000000000..63e6dd89d
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut_factory/remote_sim/fwu_dut_factory.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+
+#include "service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h"
+#include "service/fwu/test/fwu_dut/sim/sim_fwu_dut.h"
+#include "service/locator/standalone/services/fwu/fwu_service_context.h"
+
+/*
+ * A factory for constructing fwu_dut objects for remote access to
+ * the fwu_service associated with a simulated device. The factory
+ * method actually constructs two concrete fwu_dut objects, a
+ * proxy_fwu_dut and a sim_fwu_dut. The proxy_fwu_dut is returned
+ * to the caller and provides the client interface used by test
+ * cases. The sim_fwu_dut forms the backend for the standalone
+ * fwu service.
+ */
+fwu_dut *fwu_dut_factory::create(unsigned int num_locations, bool allow_partial_updates)
+{
+ /* Construct and set the simulated dut that provides the configured
+ * device and fwu service provider.
+ */
+ sim_fwu_dut *sim_dut =
+ new sim_fwu_dut(num_locations, FWU_METADATA_VERSION, allow_partial_updates);
+
+ fwu_service_context_set_provider(sim_dut->get_service_interface());
+
+ /* Construct a proxy_fwu_dut chained to the sim_fwu_dut. On deletion,
+ * the proxy_fwu_dut deletes the associated sim_fwu_dut.
+ */
+ return new proxy_fwu_dut(num_locations, FWU_METADATA_VERSION, sim_dut);
+} \ No newline at end of file
diff --git a/components/service/fwu/test/fwu_dut_factory/sim/component.cmake b/components/service/fwu/test/fwu_dut_factory/sim/component.cmake
new file mode 100644
index 000000000..3add66d3b
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut_factory/sim/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_dut_factory.cpp"
+ )
diff --git a/components/service/fwu/test/fwu_dut_factory/sim/fwu_dut_factory.cpp b/components/service/fwu/test/fwu_dut_factory/sim/fwu_dut_factory.cpp
new file mode 100644
index 000000000..b2ee1d4c4
--- /dev/null
+++ b/components/service/fwu/test/fwu_dut_factory/sim/fwu_dut_factory.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+
+#include "service/fwu/test/fwu_dut/sim/sim_fwu_dut.h"
+
+/*
+ * A factory for constructing sim_fwu_dut objects. A sim_fwu_dut is an
+ * aggregate of all storage and fwu related objects and is suitable for
+ * component level testing. The sim_fwu_dut simulates the role of the
+ * bootloader and device shutdown and boot-up.
+ */
+fwu_dut *fwu_dut_factory::create(unsigned int num_locations, bool allow_partial_updates)
+{
+ return new sim_fwu_dut(num_locations, FWU_METADATA_VERSION, allow_partial_updates);
+} \ No newline at end of file
diff --git a/components/service/fwu/test/image_directory_checker/component.cmake b/components/service/fwu/test/image_directory_checker/component.cmake
new file mode 100644
index 000000000..81df3eafb
--- /dev/null
+++ b/components/service/fwu/test/image_directory_checker/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/image_directory_checker.cpp"
+ )
diff --git a/components/service/fwu/test/image_directory_checker/image_directory_checker.cpp b/components/service/fwu/test/image_directory_checker/image_directory_checker.cpp
new file mode 100644
index 000000000..49610c170
--- /dev/null
+++ b/components/service/fwu/test/image_directory_checker/image_directory_checker.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "image_directory_checker.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+
+#include "common/uuid/uuid.h"
+
+image_directory_checker::image_directory_checker()
+ : m_buf(NULL)
+ , m_buf_size(0)
+ , m_total_read_len(0)
+{
+ alloc_buffer();
+}
+
+image_directory_checker::~image_directory_checker()
+{
+ delete[] m_buf;
+}
+
+int image_directory_checker::fetch_image_directory(fwu_client *fwu_client)
+{
+ int status = 0;
+ uint32_t stream_handle = 0;
+ size_t reported_total_len = 0;
+ struct uuid_octets uuid;
+
+ uuid_guid_octets_from_canonical(&uuid, FWU_DIRECTORY_CANONICAL_UUID);
+
+ status = fwu_client->open(&uuid, &stream_handle);
+ if (status)
+ return status;
+
+ /* Read stream until all data is read */
+ m_total_read_len = 0;
+
+ do {
+ size_t data_len_read = 0;
+ size_t requested_read_len = m_buf_size - m_total_read_len;
+
+ status = fwu_client->read_stream(stream_handle, &m_buf[m_total_read_len],
+ requested_read_len, &data_len_read,
+ &reported_total_len);
+
+ m_total_read_len += data_len_read;
+
+ assert(m_total_read_len <= reported_total_len);
+
+ if (m_total_read_len == reported_total_len) {
+ /* Read all the data */
+ break;
+ }
+
+ } while (!status);
+
+ status = fwu_client->commit(stream_handle, false);
+
+ return status;
+}
+
+size_t image_directory_checker::num_images(void) const
+{
+ size_t num_images = 0;
+
+ if (m_total_read_len >= offsetof(struct ts_fwu_image_directory, img_info_entry)) {
+ const struct ts_fwu_image_directory *header =
+ (const struct ts_fwu_image_directory *)m_buf;
+
+ num_images = header->num_images;
+ }
+
+ return num_images;
+}
+
+bool image_directory_checker::is_contents_equal(const image_directory_checker &rhs) const
+{
+ return (this->m_total_read_len > 0) && (this->m_total_read_len == rhs.m_total_read_len) &&
+ (this->m_buf && rhs.m_buf) &&
+ (memcmp(this->m_buf, rhs.m_buf, this->m_total_read_len) == 0);
+}
+
+const struct ts_fwu_image_directory *image_directory_checker::get_header(void) const
+{
+ const struct ts_fwu_image_directory *header = NULL;
+
+ if (m_total_read_len >= offsetof(struct ts_fwu_image_directory, img_info_entry))
+ header = (const struct ts_fwu_image_directory *)m_buf;
+
+ return header;
+}
+
+const struct ts_fwu_image_info_entry *
+image_directory_checker::find_entry(const struct uuid_octets *img_type_uuid) const
+{
+ const struct ts_fwu_image_info_entry *found_entry = NULL;
+
+ const struct ts_fwu_image_directory *header = get_header();
+
+ if (header) {
+ unsigned int index = 0;
+
+ while ((const uint8_t *)&header->img_info_entry[index + 1] <=
+ &m_buf[m_total_read_len]) {
+ if (uuid_is_equal(img_type_uuid->octets,
+ header->img_info_entry[index].img_type_uuid)) {
+ found_entry = &header->img_info_entry[index];
+ break;
+ }
+
+ ++index;
+ }
+ }
+
+ return found_entry;
+}
+
+void image_directory_checker::alloc_buffer(void)
+{
+ m_buf_size = offsetof(struct ts_fwu_image_directory, img_info_entry) +
+ MAX_IMAGES * sizeof(ts_fwu_image_info_entry);
+
+ m_buf = new uint8_t[m_buf_size];
+ assert(m_buf);
+}
diff --git a/components/service/fwu/test/image_directory_checker/image_directory_checker.h b/components/service/fwu/test/image_directory_checker/image_directory_checker.h
new file mode 100644
index 000000000..a8594a330
--- /dev/null
+++ b/components/service/fwu/test/image_directory_checker/image_directory_checker.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMAGE_DIRECTORY_CHECKER_H
+#define IMAGE_DIRECTORY_CHECKER_H
+
+#include <cstddef>
+#include <cstdint>
+
+#include "common/uuid/uuid.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+#include "service/fwu/test/fwu_client/fwu_client.h"
+
+/*
+ * Provides check methods for checking the contents of the image
+ * directory fetched from the update agent.
+ */
+class image_directory_checker {
+public:
+ image_directory_checker();
+ ~image_directory_checker();
+
+ int fetch_image_directory(fwu_client *fwu_client);
+
+ size_t num_images(void) const;
+
+ bool is_contents_equal(const image_directory_checker &rhs) const;
+
+ const struct ts_fwu_image_directory *get_header(void) const;
+ const struct ts_fwu_image_info_entry *
+ find_entry(const struct uuid_octets *img_type_uuid) const;
+
+private:
+ static const size_t MAX_IMAGES = 50;
+
+ void alloc_buffer(void);
+
+ uint8_t *m_buf;
+ size_t m_buf_size;
+ size_t m_total_read_len;
+};
+
+#endif /* IMAGE_DIRECTORY_CHECKER_H */
diff --git a/components/service/fwu/test/metadata_checker/component.cmake b/components/service/fwu/test/metadata_checker/component.cmake
new file mode 100644
index 000000000..a76655acc
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/component.cmake
@@ -0,0 +1,15 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/metadata_checker.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/metadata_checker_v1.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/metadata_checker_v2.cpp"
+ )
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker.cpp b/components/service/fwu/test/metadata_checker/metadata_checker.cpp
new file mode 100644
index 000000000..0f0186f77
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/metadata_checker.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "metadata_checker.h"
+
+#include <CppUTest/TestHarness.h>
+
+metadata_checker::metadata_checker(size_t max_metadata_size, metadata_fetcher *metadata_fetcher)
+ : m_metadata_fetcher(metadata_fetcher)
+ , m_meta_buf(NULL)
+ , m_meta_buf_size(max_metadata_size)
+{
+ m_metadata_fetcher->open();
+
+ m_meta_buf = new uint8_t[m_meta_buf_size];
+ CHECK_TRUE(m_meta_buf);
+}
+
+metadata_checker::~metadata_checker()
+{
+ m_metadata_fetcher->close();
+
+ delete[] m_meta_buf;
+ m_meta_buf = NULL;
+
+ delete m_metadata_fetcher;
+ m_metadata_fetcher = NULL;
+}
+
+void metadata_checker::load_metadata(void)
+{
+ m_metadata_fetcher->fetch(m_meta_buf, m_meta_buf_size);
+} \ No newline at end of file
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker.h b/components/service/fwu/test/metadata_checker/metadata_checker.h
new file mode 100644
index 000000000..cfbcfc1bd
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/metadata_checker.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef METADATA_CHECKER_H
+#define METADATA_CHECKER_H
+
+#include <cstdint>
+
+#include "service/fwu/test/metadata_fetcher/metadata_fetcher.h"
+
+/*
+ * Provides check methods for verifying that the state of fwu metadata is
+ * as expected. To allow different metadata versions to be checked, some
+ * methods are virtual and will be provided by a version specific concrete
+ * metadata_checker.
+ */
+class metadata_checker {
+public:
+ metadata_checker(size_t max_metadata_size, metadata_fetcher *metadata_fetcher);
+
+ virtual ~metadata_checker();
+
+ virtual void get_active_indices(uint32_t *active_index,
+ uint32_t *previous_active_index) = 0;
+
+ virtual void check_regular(unsigned int boot_index) = 0;
+ virtual void check_ready_for_staging(unsigned int boot_index) = 0;
+ virtual void check_ready_to_activate(unsigned int boot_index) = 0;
+ virtual void check_trial(unsigned int boot_index) = 0;
+ virtual void check_fallback_to_previous(unsigned int boot_index) = 0;
+
+protected:
+ void load_metadata(void);
+
+ metadata_fetcher *m_metadata_fetcher;
+ uint8_t *m_meta_buf;
+ size_t m_meta_buf_size;
+
+private:
+ metadata_checker(const metadata_checker &);
+ const metadata_checker &operator=(const metadata_checker &);
+};
+
+#endif /* METADATA_CHECKER_H */
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker_v1.cpp b/components/service/fwu/test/metadata_checker/metadata_checker_v1.cpp
new file mode 100644
index 000000000..f64037c8c
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/metadata_checker_v1.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "metadata_checker_v1.h"
+
+#include <CppUTest/TestHarness.h>
+
+#include "protocols/service/fwu/packed-c/metadata_v1.h"
+#include "service/fwu/agent/fw_directory.h"
+
+const size_t metadata_checker_v1::MAX_FWU_METADATA_SIZE =
+ offsetof(struct fwu_metadata, img_entry) +
+ FWU_MAX_FW_DIRECTORY_ENTRIES * sizeof(struct fwu_image_entry);
+
+metadata_checker_v1::metadata_checker_v1(metadata_fetcher *metadata_fetcher,
+ unsigned int num_images)
+ : metadata_checker(MAX_FWU_METADATA_SIZE, metadata_fetcher)
+ , m_num_images(num_images)
+{
+}
+
+metadata_checker_v1::~metadata_checker_v1()
+{
+}
+
+void metadata_checker_v1::get_active_indices(uint32_t *active_index,
+ uint32_t *previous_active_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ *active_index = metadata->active_index;
+ *previous_active_index = metadata->previous_active_index;
+}
+
+void metadata_checker_v1::check_regular(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+ CHECK_TRUE(is_all_accepted(boot_index));
+}
+
+void metadata_checker_v1::check_ready_for_staging(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+ UNSIGNED_LONGS_EQUAL(metadata->active_index, metadata->previous_active_index);
+}
+
+void metadata_checker_v1::check_ready_to_activate(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->previous_active_index);
+ CHECK_TRUE(metadata->active_index != boot_index);
+}
+
+void metadata_checker_v1::check_trial(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+ CHECK_TRUE(metadata->previous_active_index != boot_index);
+ CHECK_FALSE(is_all_accepted(boot_index));
+}
+
+void metadata_checker_v1::check_fallback_to_previous(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->previous_active_index);
+ CHECK_TRUE(metadata->active_index != boot_index);
+}
+
+bool metadata_checker_v1::is_all_accepted(unsigned int boot_index) const
+{
+ bool result = true;
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ for (unsigned int i = 0; i < m_num_images; i++) {
+ if (!metadata->img_entry[i].img_props[boot_index].accepted) {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+}
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker_v1.h b/components/service/fwu/test/metadata_checker/metadata_checker_v1.h
new file mode 100644
index 000000000..36bbbe927
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/metadata_checker_v1.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef METADATA_CHECKER_V1_H
+#define METADATA_CHECKER_V1_H
+
+#include "metadata_checker.h"
+
+/*
+ * A metadata_checker for FWU-A V1 metadata
+ */
+class metadata_checker_v1 : public metadata_checker {
+public:
+ metadata_checker_v1(metadata_fetcher *metadata_fetcher, unsigned int num_images);
+
+ virtual ~metadata_checker_v1();
+
+ void get_active_indices(uint32_t *active_index, uint32_t *previous_active_index) override;
+
+ void check_regular(unsigned int boot_index) override;
+ void check_ready_for_staging(unsigned int boot_index) override;
+ void check_ready_to_activate(unsigned int boot_index) override;
+ void check_trial(unsigned int boot_index) override;
+ void check_fallback_to_previous(unsigned int boot_index) override;
+
+private:
+ static const size_t MAX_FWU_METADATA_SIZE;
+
+ bool is_all_accepted(unsigned int boot_index) const;
+
+ unsigned int m_num_images;
+};
+
+#endif /* METADATA_CHECKER_V1_H */
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker_v2.cpp b/components/service/fwu/test/metadata_checker/metadata_checker_v2.cpp
new file mode 100644
index 000000000..e51ed3251
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/metadata_checker_v2.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "metadata_checker_v2.h"
+
+#include <CppUTest/TestHarness.h>
+
+#include "protocols/service/fwu/packed-c/metadata_v2.h"
+#include "service/fwu/agent/fw_directory.h"
+
+const size_t metadata_checker_v2::MAX_FWU_METADATA_SIZE =
+ sizeof(struct fwu_metadata) + offsetof(struct fwu_fw_store_desc, img_entry) +
+ sizeof(struct fwu_image_entry) * FWU_MAX_FW_DIRECTORY_ENTRIES;
+
+metadata_checker_v2::metadata_checker_v2(metadata_fetcher *metadata_fetcher,
+ unsigned int num_images)
+ : metadata_checker(MAX_FWU_METADATA_SIZE, metadata_fetcher)
+{
+}
+
+metadata_checker_v2::~metadata_checker_v2()
+{
+}
+
+void metadata_checker_v2::get_active_indices(uint32_t *active_index,
+ uint32_t *previous_active_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ *active_index = metadata->active_index;
+ *previous_active_index = metadata->previous_active_index;
+}
+
+void metadata_checker_v2::check_regular(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+
+ BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_ACCEPTED, metadata->bank_state[boot_index]);
+}
+
+void metadata_checker_v2::check_ready_for_staging(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+
+ BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_ACCEPTED, metadata->bank_state[boot_index]);
+ BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_INVALID,
+ metadata->bank_state[alternate_bank_index(boot_index)]);
+}
+
+void metadata_checker_v2::check_ready_to_activate(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->previous_active_index);
+ CHECK_TRUE(metadata->active_index != boot_index);
+
+ BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_VALID, metadata->bank_state[metadata->active_index]);
+}
+
+void metadata_checker_v2::check_trial(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+ CHECK_TRUE(metadata->previous_active_index != boot_index);
+
+ BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_VALID, metadata->bank_state[boot_index]);
+}
+
+void metadata_checker_v2::check_fallback_to_previous(unsigned int boot_index)
+{
+ load_metadata();
+
+ struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+ UNSIGNED_LONGS_EQUAL(boot_index, metadata->previous_active_index);
+ CHECK_TRUE(metadata->active_index != boot_index);
+
+ BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_ACCEPTED, metadata->bank_state[boot_index]);
+}
+
+unsigned int metadata_checker_v2::alternate_bank_index(unsigned int bank_index)
+{
+ return (bank_index == 0) ? 1 : 0;
+} \ No newline at end of file
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker_v2.h b/components/service/fwu/test/metadata_checker/metadata_checker_v2.h
new file mode 100644
index 000000000..8a13da287
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/metadata_checker_v2.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef METADATA_CHECKER_V2_H
+#define METADATA_CHECKER_V2_H
+
+#include "metadata_checker.h"
+
+/*
+ * A metadata_checker for FWU-A V2 metadata
+ */
+class metadata_checker_v2 : public metadata_checker {
+public:
+ metadata_checker_v2(metadata_fetcher *metadata_fetcher, unsigned int num_images);
+
+ virtual ~metadata_checker_v2();
+
+ void get_active_indices(uint32_t *active_index, uint32_t *previous_active_index) override;
+
+ void check_regular(unsigned int boot_index) override;
+ void check_ready_for_staging(unsigned int boot_index) override;
+ void check_ready_to_activate(unsigned int boot_index) override;
+ void check_trial(unsigned int boot_index) override;
+ void check_fallback_to_previous(unsigned int boot_index) override;
+
+private:
+ static unsigned int alternate_bank_index(unsigned int bank_index);
+
+ static const size_t MAX_FWU_METADATA_SIZE;
+};
+
+#endif /* METADATA_CHECKER_V2_H */
diff --git a/components/service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.cpp b/components/service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.cpp
new file mode 100644
index 000000000..77d211cb0
--- /dev/null
+++ b/components/service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "client_metadata_fetcher.h"
+
+#include <CppUTest/TestHarness.h>
+#include <cstring>
+
+#include "common/uuid/uuid.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+
+client_metadata_fetcher::client_metadata_fetcher(fwu_client *fwu_client)
+ : metadata_fetcher()
+ , m_fwu_client(fwu_client)
+{
+}
+
+client_metadata_fetcher::~client_metadata_fetcher()
+{
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+}
+
+void client_metadata_fetcher::open()
+{
+}
+
+void client_metadata_fetcher::close(void)
+{
+}
+
+void client_metadata_fetcher::fetch(uint8_t *buf, size_t buf_size)
+{
+ int status = 0;
+ uint32_t stream_handle = 0;
+ struct uuid_octets uuid;
+
+ uuid_guid_octets_from_canonical(&uuid, FWU_METADATA_CANONICAL_UUID);
+
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(0, status);
+
+ size_t read_len = 0;
+ size_t total_len = 0;
+
+ status = m_fwu_client->read_stream(stream_handle, buf, buf_size, &read_len, &total_len);
+ LONGS_EQUAL(0, status);
+
+ m_fwu_client->commit(stream_handle, false);
+}
diff --git a/components/service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.h b/components/service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.h
new file mode 100644
index 000000000..0ced2b634
--- /dev/null
+++ b/components/service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CLIENT_METADATA_FETCHER_H
+#define CLIENT_METADATA_FETCHER_H
+
+#include "service/fwu/test/fwu_client/fwu_client.h"
+#include "service/fwu/test/metadata_fetcher/metadata_fetcher.h"
+
+/*
+ * A metadata_fetcher that fetches fwu metadata using the FWU
+ * ABI streaming interface via an fwu_client. This relies on
+ * support for streamed reading of metadata via the public
+ * service interface. A suitable fwu_client must be constructed
+ * with 'new' and exclusive ownership passed to the
+ * client_metadata_fetcher via its constructor. The
+ * client_metadata_fetcher is responsible for deleting the
+ * fwu_client when it no longer needs it.
+ */
+class client_metadata_fetcher : public metadata_fetcher {
+public:
+ explicit client_metadata_fetcher(fwu_client *fwu_client);
+
+ ~client_metadata_fetcher();
+
+ void open();
+ void close(void);
+ void fetch(uint8_t *buf, size_t buf_size);
+
+private:
+ fwu_client *m_fwu_client;
+};
+
+#endif /* CLIENT_METADATA_FETCHER_H */
diff --git a/components/service/fwu/test/metadata_fetcher/client/component.cmake b/components/service/fwu/test/metadata_fetcher/client/component.cmake
new file mode 100644
index 000000000..5aefa45d3
--- /dev/null
+++ b/components/service/fwu/test/metadata_fetcher/client/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/client_metadata_fetcher.cpp"
+ )
diff --git a/components/service/fwu/test/metadata_fetcher/metadata_fetcher.h b/components/service/fwu/test/metadata_fetcher/metadata_fetcher.h
new file mode 100644
index 000000000..97f18dbec
--- /dev/null
+++ b/components/service/fwu/test/metadata_fetcher/metadata_fetcher.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef METADATA_FETCHER_H
+#define METADATA_FETCHER_H
+
+#include <cstddef>
+#include <cstdint>
+
+/*
+ * The metadata_fetcher provides an interface for fetching the current
+ * fwu metadata and writing it to a presented buffer. Different concrete
+ * fetching methods can be used for alternative test configurations.
+ */
+class metadata_fetcher {
+public:
+ metadata_fetcher()
+ {
+ }
+
+ virtual ~metadata_fetcher()
+ {
+ }
+
+ virtual void open(void) = 0;
+ virtual void close(void) = 0;
+ virtual void fetch(uint8_t *buf, size_t buf_size) = 0;
+};
+
+#endif /* METADATA_FETCHER_H */
diff --git a/components/service/fwu/test/metadata_fetcher/volume/component.cmake b/components/service/fwu/test/metadata_fetcher/volume/component.cmake
new file mode 100644
index 000000000..89fe63d7e
--- /dev/null
+++ b/components/service/fwu/test/metadata_fetcher/volume/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/volume_metadata_fetcher.cpp"
+ )
diff --git a/components/service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.cpp b/components/service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.cpp
new file mode 100644
index 000000000..b766e8500
--- /dev/null
+++ b/components/service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "volume_metadata_fetcher.h"
+
+#include <CppUTest/TestHarness.h>
+#include <cstring>
+
+#include "media/volume/volume.h"
+
+volume_metadata_fetcher::volume_metadata_fetcher(const struct uuid_octets *partition_guid,
+ struct block_store *block_store)
+ : metadata_fetcher()
+ , m_meta_block_volume()
+ , m_meta_volume(NULL)
+{
+ int status = block_volume_init(&m_meta_block_volume, block_store, partition_guid,
+ &m_meta_volume);
+ LONGS_EQUAL(0, status);
+ CHECK_TRUE(m_meta_volume);
+}
+
+volume_metadata_fetcher::~volume_metadata_fetcher()
+{
+ block_volume_deinit(&m_meta_block_volume);
+}
+
+void volume_metadata_fetcher::open(void)
+{
+ int status = volume_open(m_meta_volume);
+ LONGS_EQUAL(0, status);
+}
+
+void volume_metadata_fetcher::close(void)
+{
+ volume_close(m_meta_volume);
+}
+
+void volume_metadata_fetcher::fetch(uint8_t *buf, size_t buf_size)
+{
+ /* Trash the old data */
+ memset(buf, 0xff, buf_size);
+
+ int status = volume_seek(m_meta_volume, IO_SEEK_SET, 0);
+ LONGS_EQUAL(0, status);
+
+ size_t length_read = 0;
+
+ status = volume_read(m_meta_volume, (uintptr_t)buf, buf_size, &length_read);
+
+ LONGS_EQUAL(0, status);
+ UNSIGNED_LONGS_EQUAL(buf_size, length_read);
+}
diff --git a/components/service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.h b/components/service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.h
new file mode 100644
index 000000000..200a8cf29
--- /dev/null
+++ b/components/service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VOLUME_METADATA_FETCHER_H
+#define VOLUME_METADATA_FETCHER_H
+
+#include "media/volume/block_volume/block_volume.h"
+#include "service/fwu/test/metadata_fetcher/metadata_fetcher.h"
+
+/*
+ * A metadata_fetcher that fetches fwu metadata from a storage volume
+ * that provides access to the disk partition used for fwu metadata.
+ */
+class volume_metadata_fetcher : public metadata_fetcher {
+public:
+ volume_metadata_fetcher(const struct uuid_octets *partition_guid,
+ struct block_store *block_store);
+
+ ~volume_metadata_fetcher();
+
+ void open(void);
+ void close(void);
+ void fetch(uint8_t *buf, size_t buf_size);
+
+private:
+ struct block_volume m_meta_block_volume;
+ struct volume *m_meta_volume;
+};
+
+#endif /* VOLUME_METADATA_FETCHER_H */
diff --git a/components/service/fwu/test/ref_scenarios/component.cmake b/components/service/fwu/test/ref_scenarios/component.cmake
new file mode 100644
index 000000000..87c6369ea
--- /dev/null
+++ b/components/service/fwu/test/ref_scenarios/component.cmake
@@ -0,0 +1,19 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/image_directory_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/invalid_behaviour_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/update_scenario_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/power_failure_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/rollback_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/oversize_image_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/update_fmp_tests.cpp"
+ )
diff --git a/components/service/fwu/test/ref_scenarios/image_directory_tests.cpp b/components/service/fwu/test/ref_scenarios/image_directory_tests.cpp
new file mode 100644
index 000000000..453525b37
--- /dev/null
+++ b/components/service/fwu/test/ref_scenarios/image_directory_tests.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <cstdint>
+#include <vector>
+
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+#include "service/fwu/test/image_directory_checker/image_directory_checker.h"
+
+/*
+ * Tests that focus on retrieving and checking the contents of the image
+ * directory returned by the update agent. The image directory is intended
+ * to provide an up-to-date view of updatable firmware components.
+ */
+TEST_GROUP(FwuImageDirectoryTests)
+{
+ void setup()
+ {
+ m_dut = NULL;
+ m_fwu_client = NULL;
+ }
+
+ void teardown()
+ {
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+
+ delete m_dut;
+ m_dut = NULL;
+ }
+
+ fwu_dut *m_dut;
+ fwu_client *m_fwu_client;
+};
+
+TEST(FwuImageDirectoryTests, streamedReads)
+{
+ int status = 0;
+
+ /* Construct and boot a DUT with a couple of fw locations */
+ m_dut = fwu_dut_factory::create(2);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_dut->boot();
+
+ /* As a reference, fetch the image directory with the default buffer
+ * used by an image_directory_checker.
+ */
+ image_directory_checker checker_a;
+
+ status = checker_a.fetch_image_directory(m_fwu_client);
+ LONGS_EQUAL(0, status);
+
+ /* Construct another image_directory_checker and repeatedly
+ * fetch and compare the results for consistency.
+ */
+ image_directory_checker checker_b;
+
+ for (unsigned int i = 0; i < 100; ++i) {
+ /* Try lots of reads */
+ status = checker_b.fetch_image_directory(m_fwu_client);
+ LONGS_EQUAL(0, status);
+
+ /* Always expect the read data to be consistent */
+ CHECK_TRUE(checker_a.is_contents_equal(checker_b));
+ }
+}
+
+TEST(FwuImageDirectoryTests, streamRecycling)
+{
+ std::vector<uint32_t> stream_handles;
+ struct uuid_octets uuid;
+
+ uuid_guid_octets_from_canonical(&uuid, FWU_DIRECTORY_CANONICAL_UUID);
+
+ /* Construct and boot a DUT with a couple of fw locations */
+ m_dut = fwu_dut_factory::create(2);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_dut->boot();
+
+ /* Expect to be able to keep opening streams, beyond the capacity of
+ * the update_agent. The update_agent implements a least recently used
+ * recycling strategy for streams to defend against a denial-of-service
+ * attack where streams are opened but never closed.
+ */
+ for (unsigned int i = 0; i < 200; ++i) {
+ int status = 0;
+ uint32_t stream_handle = 0;
+
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(0, status);
+
+ stream_handles.push_back(stream_handle);
+ }
+
+ /* Only the most recently opened streams should still be opened. Expect
+ * older ones to have been cancelled. Test this by closing streams in
+ * reverse chronological order.
+ */
+ unsigned int successfully_closed_count = 0;
+ unsigned int cancelled_count = 0;
+ unsigned int stream_index = stream_handles.size();
+
+ CHECK_TRUE(stream_index > 0);
+
+ do {
+ int status = 0;
+
+ --stream_index;
+
+ status = m_fwu_client->commit(stream_handles[stream_index], false);
+
+ if (!status) {
+ /* Operation successful so expect this to be a recently opened stream */
+ LONGS_EQUAL(0, cancelled_count);
+ ++successfully_closed_count;
+ } else {
+ /* Operation failed so expect this to be an older stream */
+ CHECK_TRUE(successfully_closed_count > 0);
+ ++cancelled_count;
+ }
+ } while (stream_index > 0);
+
+ CHECK_TRUE(successfully_closed_count > 0);
+ CHECK_TRUE(cancelled_count > 0);
+}
+
+TEST(FwuImageDirectoryTests, singleFwLocation)
+{
+ int status = 0;
+
+ /* Construct and boot a DUT with a single fw location. This configuration
+ * is typical of a TF-A based device where all firmware is loaded from a
+ * FIP image. A/B banks are stored in separate disk partitions.
+ */
+ m_dut = fwu_dut_factory::create(1);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_dut->boot();
+
+ image_directory_checker checker;
+
+ status = checker.fetch_image_directory(m_fwu_client);
+ LONGS_EQUAL(0, status);
+
+ const struct ts_fwu_image_directory *dir_header = checker.get_header();
+
+ /* Expect directory header to reflect correct values */
+ CHECK_TRUE(dir_header);
+ UNSIGNED_LONGS_EQUAL(offsetof(struct ts_fwu_image_directory, img_info_entry),
+ dir_header->img_info_offset);
+ UNSIGNED_LONGS_EQUAL(sizeof(struct ts_fwu_image_info_entry), dir_header->img_info_size);
+ UNSIGNED_LONGS_EQUAL(2, dir_header->directory_version);
+ UNSIGNED_LONGS_EQUAL(1, dir_header->correct_boot);
+ UNSIGNED_LONGS_EQUAL(0, dir_header->reserved);
+ CHECK_TRUE(dir_header->num_images >= 1);
+
+ /* Expect an image entry for whole volume updates for location id zero */
+ struct uuid_octets expected_img_type_uuid;
+
+ m_dut->whole_volume_image_type_uuid(0, &expected_img_type_uuid);
+
+ const struct ts_fwu_image_info_entry *image_entry =
+ checker.find_entry(&expected_img_type_uuid);
+
+ CHECK_TRUE(image_entry);
+}
+
+TEST(FwuImageDirectoryTests, multipleFwLocations)
+{
+ int status = 0;
+ unsigned int num_locations = 3;
+
+ /* Construct and boot a DUT with multiple fw locations. This configuration
+ * will be typical of devices where firmware components distributed
+ * across multiple disk partitions.
+ */
+ m_dut = fwu_dut_factory::create(num_locations);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_dut->boot();
+
+ image_directory_checker checker;
+
+ status = checker.fetch_image_directory(m_fwu_client);
+ LONGS_EQUAL(0, status);
+
+ const struct ts_fwu_image_directory *dir_header = checker.get_header();
+
+ /* Expect directory header to reflect correct values */
+ CHECK_TRUE(dir_header);
+ UNSIGNED_LONGS_EQUAL(2, dir_header->directory_version);
+ UNSIGNED_LONGS_EQUAL(1, dir_header->correct_boot);
+ CHECK_TRUE(dir_header->num_images >= num_locations);
+
+ for (unsigned int location_id = 0; location_id < num_locations; location_id++) {
+ /* Expect an image entry for whole volume updates for each location */
+ struct uuid_octets expected_img_type_uuid;
+
+ m_dut->whole_volume_image_type_uuid(0, &expected_img_type_uuid);
+
+ const struct ts_fwu_image_info_entry *image_entry =
+ checker.find_entry(&expected_img_type_uuid);
+
+ CHECK_TRUE(image_entry);
+ }
+}
+
+TEST(FwuImageDirectoryTests, zeroFwLocations)
+{
+ int status = 0;
+
+ /* Construct and boot a DUT with no fw locations. This configuration
+ * will be typical of a device with no Swd accessible flash. With
+ * this sort of configuration, update images will be installed from
+ * Nwd.
+ */
+ m_dut = fwu_dut_factory::create(0);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_dut->boot();
+
+ image_directory_checker checker;
+
+ status = checker.fetch_image_directory(m_fwu_client);
+ LONGS_EQUAL(0, status);
+
+ const struct ts_fwu_image_directory *dir_header = checker.get_header();
+
+ /* Expect directory header to reflect correct values */
+ CHECK_TRUE(dir_header);
+ UNSIGNED_LONGS_EQUAL(2, dir_header->directory_version);
+ UNSIGNED_LONGS_EQUAL(1, dir_header->correct_boot);
+
+ /* The DUT uses a direct_fw_inspector to populate the fw directory.
+ * This relies on direct access to fw storage to determine what components
+ * should be reflected in the image directory. In practice, for a single
+ * flash system, an alternative fw inspector will be used.
+ */
+ UNSIGNED_LONGS_EQUAL(0, dir_header->num_images);
+} \ No newline at end of file
diff --git a/components/service/fwu/test/ref_scenarios/invalid_behaviour_tests.cpp b/components/service/fwu/test/ref_scenarios/invalid_behaviour_tests.cpp
new file mode 100644
index 000000000..100940a63
--- /dev/null
+++ b/components/service/fwu/test/ref_scenarios/invalid_behaviour_tests.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <vector>
+
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+#include "service/fwu/test/image_directory_checker/image_directory_checker.h"
+
+/*
+ * Tests that check defenses against invalid behaviour from a client.
+ */
+TEST_GROUP(FwuInvalidBehaviourTests)
+{
+ void setup()
+ {
+ m_dut = NULL;
+ m_fwu_client = NULL;
+ m_dir_checker = new image_directory_checker;
+ }
+
+ void teardown()
+ {
+ delete m_dir_checker;
+ m_dir_checker = NULL;
+
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+
+ delete m_dut;
+ m_dut = NULL;
+ }
+
+ fwu_dut *m_dut;
+ image_directory_checker *m_dir_checker;
+ fwu_client *m_fwu_client;
+};
+
+TEST(FwuInvalidBehaviourTests, invalidOperationsInRegular)
+{
+ int status = 0;
+ uint32_t stream_handle = 0;
+ struct uuid_octets uuid;
+
+ /* Construct and boot a DUT with a single fw location. Assume
+ * an initial transition to the REGULAR FWU state.
+ */
+ m_dut = fwu_dut_factory::create(1);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_dut->boot();
+
+ /* End staging without having entered STAGING */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Cancel staging without having entered STAGING */
+ status = m_fwu_client->cancel_staging();
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Open a fw image when not STAGING */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Write to a stream when not STAGING. Note also that it's not possible
+ * to obtain a stream handle outside of STAGING so use an arbitrary value.
+ * There are a few possible failure cases, depending on whether the stream
+ * handle qualifies an open stream or not. For this case, it shouldn't.
+ */
+ std::string image_data("some image data...");
+
+ stream_handle = 67;
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_UNKNOWN, status);
+
+ /* An attempt to commit with an invalid handle should fail in a similar way */
+ stream_handle = 771;
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_UNKNOWN, status);
+}
+
+TEST(FwuInvalidBehaviourTests, invalidOperationsInStaging)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+
+ /* Construct and boot a DUT with a 3 fw locations and with
+ * the policy not to allow partial updates. This means that
+ * an incoming update must include image updates for all
+ * locations.
+ *
+ * Assume an initial transition to the REGULAR FWU state.
+ */
+ m_dut = fwu_dut_factory::create(3, false);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_dut->boot();
+
+ /* Expect to be able to transition to STAGING */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* And re-enter STAGING (implicit cancel) */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Opening a couple of streams for installing images associated
+ * with two of the three updatable locations.
+ */
+ uint32_t stream_handle1 = 0;
+ uint32_t stream_handle2 = 0;
+
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle1);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ m_dut->whole_volume_image_type_uuid(1, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle2);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Attempting to end staging with open install streams should fail */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_BUSY, status);
+
+ /* Commit without actually writing any image data. This would occur
+ * if an incoming update package contained zero length images. This
+ * could be interpreted as an image delete. As a delete operation
+ * is not supported by the raw_installer used by the DUT, expect
+ * the commit operations to fail.
+ */
+ status = m_fwu_client->commit(stream_handle1, false);
+ LONGS_EQUAL(FWU_STATUS_NOT_AVAILABLE, status);
+ status = m_fwu_client->commit(stream_handle2, false);
+ LONGS_EQUAL(FWU_STATUS_NOT_AVAILABLE, status);
+
+ /* Expect accepting images to be denied while STAGING */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->accept(&uuid);
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ m_dut->whole_volume_image_type_uuid(1, &uuid);
+ status = m_fwu_client->accept(&uuid);
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Expect rolling back to previous version to also be denied while STAGING */
+ status = m_fwu_client->select_previous();
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Attempting to end staging when errors occurred during the installation
+ * process should fail.
+ */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_NOT_AVAILABLE, status);
+
+ /* Because the end_staging failed, expect to be still in STAGING.
+ * A call to cancel_staging is required to force a transition back to
+ * REGULAR.
+ */
+ status = m_fwu_client->cancel_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Cancelling again though should fail. */
+ status = m_fwu_client->cancel_staging();
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+}
+
+TEST(FwuInvalidBehaviourTests, invalidOperationsInTrial)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+
+ /* Construct and boot a DUT with a 3 fw locations and with
+ * the policy to allow partial updates. With this policy
+ * not all locations need to be updated for a viable update.
+ */
+ m_dut = fwu_dut_factory::create(3, true);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_dut->boot();
+
+ /* Expect to be able to transition to STAGING */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Install an image into location 0 */
+ uint32_t stream_handle = 0;
+
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Although only one location was updated, the DUT accepts partial
+ * updates so ending staging should be happy.
+ */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* If we've transitioned to TRAIL, attempting to begin staging
+ * again should be denied.
+ */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Activate the update. We'd expect the update to have been installed
+ * in a different bank from the boot bank.
+ */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* If all's well, the DUT should have rebooted to TRIAL. Confirm this by
+ * trying to begin staging - this should be denied.
+ */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* All other staging related operations should also be denied */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ status = m_fwu_client->cancel_staging();
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Attempting to install images should also be denied */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Reading the image directory should be ok though */
+ status = m_dir_checker->fetch_image_directory(m_fwu_client);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Reverting to the previous version should be ok */
+ status = m_fwu_client->select_previous();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Should have transitioned back to REGULAR */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->cancel_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ m_dut->shutdown();
+}
diff --git a/components/service/fwu/test/ref_scenarios/oversize_image_tests.cpp b/components/service/fwu/test/ref_scenarios/oversize_image_tests.cpp
new file mode 100644
index 000000000..c8d91a14c
--- /dev/null
+++ b/components/service/fwu/test/ref_scenarios/oversize_image_tests.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <vector>
+
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+#include "service/fwu/test/image_directory_checker/image_directory_checker.h"
+
+/*
+ * Tests that check behaviour when oversize images are installed.
+ */
+TEST_GROUP(FwuOversizeImageTests)
+{
+ void setup()
+ {
+ m_dut = NULL;
+ m_fwu_client = NULL;
+ }
+
+ void teardown()
+ {
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+
+ delete m_dut;
+ m_dut = NULL;
+ }
+
+ size_t max_image_size(const struct uuid_octets *uuid)
+ {
+ image_directory_checker dir_checker;
+
+ int status = dir_checker.fetch_image_directory(m_fwu_client);
+ LONGS_EQUAL(0, status);
+
+ const struct ts_fwu_image_info_entry *img_entry = dir_checker.find_entry(uuid);
+ CHECK_TRUE(img_entry);
+
+ return static_cast<size_t>(img_entry->img_max_size);
+ }
+
+ fwu_dut *m_dut;
+ fwu_client *m_fwu_client;
+};
+
+TEST(FwuOversizeImageTests, maxSizeInstall)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Performs an update with an image of the maximum size advertised by
+ * the image directory.
+ */
+ m_dut = fwu_dut_factory::create(1, false);
+ m_fwu_client = m_dut->create_fwu_client();
+
+ m_dut->boot();
+
+ /* Generate image that should just fit */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ size_t img_size = max_image_size(&uuid);
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data, img_size);
+
+ /* Install the image */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Check for reboot with no errors */
+ m_dut->shutdown();
+ m_dut->boot();
+}
+
+TEST(FwuOversizeImageTests, oversizeInstallCancelStaging)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Performs an update with an oversized image where the client
+ * cancels staging on seeing the error. This is the expected
+ * client behavior when an error occurs during installation.
+ */
+ m_dut = fwu_dut_factory::create(1, false);
+ m_fwu_client = m_dut->create_fwu_client();
+
+ m_dut->boot();
+
+ /* Generate image that's too big */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ size_t img_size = max_image_size(&uuid) + 1;
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data, img_size);
+
+ /* Install the image */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_OUT_OF_BOUNDS, status);
+
+ /* Client response to the error by cancelling staging */
+ status = m_fwu_client->cancel_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Check for reboot with no errors */
+ m_dut->shutdown();
+ m_dut->boot();
+}
+
+TEST(FwuOversizeImageTests, oversizeInstallEndStaging)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Performs an update with an oversized image where the client
+ * attempts to proceed with the update beyond the point where an error
+ * was reported due to an attempt to install an oversized image.
+ */
+ m_dut = fwu_dut_factory::create(1, false);
+ m_fwu_client = m_dut->create_fwu_client();
+
+ m_dut->boot();
+
+ /* Generate image that's too big */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ size_t img_size = max_image_size(&uuid) + 1;
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data, img_size);
+
+ /* Install the image */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_OUT_OF_BOUNDS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Client has ignored the error and proceeded to end staging. Because
+ * the DUT was configured to not support partial updates, expect end_staging
+ * to fail.
+ */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_NOT_AVAILABLE, status);
+
+ /* Check for reboot with no errors */
+ m_dut->shutdown();
+ m_dut->boot();
+}
+
+TEST(FwuOversizeImageTests, oversizeInstallMultiLocationEndStaging)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Performs an update with one oversized image when the DUT has
+ * multiple locations. This checks handling when some installs are
+ * successful but one fails because the image is too big. Because
+ * the DUT allows partial updates, if the client proceeds to
+ * finalize the update, any images handled by the errored installer
+ * will be ignored and treated as if they weren't updated.
+ */
+ m_dut = fwu_dut_factory::create(3, true);
+ m_fwu_client = m_dut->create_fwu_client();
+
+ m_dut->boot();
+
+ /* Perform multi-image update transaction */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Install good image for location 0 */
+ std::vector<uint8_t> image_data;
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ size_t img_size = max_image_size(&uuid);
+ m_dut->generate_image_data(&image_data, img_size);
+
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Install oversized image for location 1 */
+ m_dut->whole_volume_image_type_uuid(1, &uuid);
+ img_size = max_image_size(&uuid) + 1;
+ m_dut->generate_image_data(&image_data, img_size);
+
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_OUT_OF_BOUNDS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Install good image for location 2 */
+ m_dut->whole_volume_image_type_uuid(2, &uuid);
+ img_size = max_image_size(&uuid);
+ m_dut->generate_image_data(&image_data, img_size);
+
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Expect end staging to be successful and that the errored image is
+ * excluded from the update. This should be confirmed by the following
+ * boot being error-free.
+ */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Check for reboot with no errors */
+ m_dut->shutdown();
+ m_dut->boot();
+}
diff --git a/components/service/fwu/test/ref_scenarios/power_failure_tests.cpp b/components/service/fwu/test/ref_scenarios/power_failure_tests.cpp
new file mode 100644
index 000000000..a009e8c2c
--- /dev/null
+++ b/components/service/fwu/test/ref_scenarios/power_failure_tests.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <vector>
+
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+/*
+ * Tests to check that FWU metadata is never left in an invalid state
+ * during the update process when unexpected power failures occur. Power
+ * failures are simulated by shutting down the DUT after each write to
+ * metadata and re-boot to check all conditions for a successful boot
+ * are met.
+ */
+TEST_GROUP(FwuPowerFailureTests)
+{
+ void setup()
+ {
+ m_dut = NULL;
+ m_fwu_client = NULL;
+ m_metadata_checker = NULL;
+ }
+
+ void teardown()
+ {
+ delete m_metadata_checker;
+ m_metadata_checker = NULL;
+
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+
+ delete m_dut;
+ m_dut = NULL;
+ }
+
+ fwu_dut *m_dut;
+ metadata_checker *m_metadata_checker;
+ fwu_client *m_fwu_client;
+};
+
+TEST(FwuPowerFailureTests, powerFailureDuringStaging)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+ std::vector<uint8_t> image_data;
+
+ m_dut = fwu_dut_factory::create(3, true);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_metadata_checker = m_dut->create_metadata_checker();
+
+ m_dut->boot();
+
+ /* Check assumptions about the first boot. */
+ struct boot_info boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Begin staging */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ /* Power cycle */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Expect to reboot into the regular state without errors */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Begin staging again */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ /* Start installing an image but don't commit it */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Power cycle */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Expect to reboot into the regular state without errors */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Begin staging again */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ /* Start installing an image but this time commit it without ending staging */
+ m_dut->whole_volume_image_type_uuid(1, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Power cycle */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Expect to reboot into the regular state without errors */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_regular(boot_info.boot_index);
+}
+
+TEST(FwuPowerFailureTests, powerFailureDuringTrial)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+ std::vector<uint8_t> image_data;
+
+ m_dut = fwu_dut_factory::create(3, true);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_metadata_checker = m_dut->create_metadata_checker();
+
+ m_dut->boot();
+
+ /* Check assumptions about the first boot. */
+ struct boot_info boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Begin staging */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ /* Install a partial update */
+ m_dut->whole_volume_image_type_uuid(2, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Transition to the trial state */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_to_activate(boot_info.boot_index);
+
+ /* Power cycle */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Check the metadata after the reboot to activate the update */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_trial(boot_info.boot_index);
+
+ /* Power cycle again */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Check trial is still active */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_trial(boot_info.boot_index);
+
+ /* Power cycle again */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Check trial is still active */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_trial(boot_info.boot_index);
+
+ /* Only image 2 should need accepting as it was the only image updated */
+ m_dut->whole_volume_image_type_uuid(2, &uuid);
+ status = m_fwu_client->accept(&uuid);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Power cycle again */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Check transition to regular */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_regular(boot_info.boot_index);
+}
diff --git a/components/service/fwu/test/ref_scenarios/rollback_tests.cpp b/components/service/fwu/test/ref_scenarios/rollback_tests.cpp
new file mode 100644
index 000000000..db77a3f84
--- /dev/null
+++ b/components/service/fwu/test/ref_scenarios/rollback_tests.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <vector>
+
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+
+/*
+ * Tests that check update rollback during the trial state where an
+ * update is abandoned and the previous active image becomes the active
+ * image.
+ */
+TEST_GROUP(FwuRollbackTests)
+{
+ void setup()
+ {
+ m_dut = NULL;
+ m_fwu_client = NULL;
+ m_metadata_checker = NULL;
+ }
+
+ void teardown()
+ {
+ delete m_metadata_checker;
+ m_metadata_checker = NULL;
+
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+
+ delete m_dut;
+ m_dut = NULL;
+ }
+
+ fwu_dut *m_dut;
+ metadata_checker *m_metadata_checker;
+ fwu_client *m_fwu_client;
+};
+
+/*
+ * A client requests select_previous after staging an update but before the
+ * restart that activates the update.
+ */
+TEST(FwuRollbackTests, selectPreviousPriorToActivation)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Create DUT */
+ m_dut = fwu_dut_factory::create(1, false);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_metadata_checker = m_dut->create_metadata_checker();
+
+ m_dut->boot();
+
+ struct boot_info boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Note the pre-update bank index */
+ unsigned int pre_update_bank_index = boot_info.boot_index;
+
+ /* Install the update */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_to_activate(boot_info.boot_index);
+
+ /* Rollback to pre-update state - note that the update has not yet
+ * been activated.
+ */
+ status = m_fwu_client->select_previous();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Reboot */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Check that the pre-update state is restored */
+ boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ UNSIGNED_LONGS_EQUAL(pre_update_bank_index, boot_info.boot_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+}
+
+/*
+ * A client requests select_previous after activating the update.
+ */
+TEST(FwuRollbackTests, selectPreviousAfterActivation)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Create DUT */
+ m_dut = fwu_dut_factory::create(1, false);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_metadata_checker = m_dut->create_metadata_checker();
+
+ m_dut->boot();
+
+ struct boot_info boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Note the pre-update bank index */
+ unsigned int pre_update_bank_index = boot_info.boot_index;
+
+ /* Install the update */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_to_activate(boot_info.boot_index);
+
+ /* Reboot to activate update*/
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Expect to be in trial state */
+ boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ m_metadata_checker->check_trial(boot_info.boot_index);
+
+ /* Rollback to pre-update state */
+ status = m_fwu_client->select_previous();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Reboot */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Check that the pre-update state is restored */
+ boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ UNSIGNED_LONGS_EQUAL(pre_update_bank_index, boot_info.boot_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+}
+
+/*
+ * The bootloader fails to boot from the active bank so it falls back
+ * to booting from the previous active bank/
+ */
+TEST(FwuRollbackTests, bootloaderFallback)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Create DUT */
+ m_dut = fwu_dut_factory::create(1, false);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_metadata_checker = m_dut->create_metadata_checker();
+
+ m_dut->boot();
+
+ struct boot_info boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Note the pre-update bank index */
+ unsigned int pre_update_bank_index = boot_info.boot_index;
+
+ /* Install the update */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_to_activate(boot_info.boot_index);
+
+ /* Reboot to activate update but simulate a failure to boot from the
+ * new active bank. The bootloader instead boots from the previous
+ * active bank.
+ */
+ m_dut->shutdown();
+ m_dut->boot(false);
+
+ /* Expect the bootloader to have booted from the previous active bank. */
+ boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(pre_update_bank_index, boot_info.boot_index);
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.previous_active_index);
+ CHECK_FALSE(boot_info.previous_active_index == boot_info.active_index);
+
+ /* Expect the update agent to have spotted the bootloader decision and
+ * modified the metadata to prevent a repeat of the boot failure.
+ */
+ uint32_t active_index;
+ uint32_t previous_active_index;
+
+ m_metadata_checker->get_active_indices(&active_index, &previous_active_index);
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, active_index);
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, previous_active_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+} \ No newline at end of file
diff --git a/components/service/fwu/test/ref_scenarios/update_fmp_tests.cpp b/components/service/fwu/test/ref_scenarios/update_fmp_tests.cpp
new file mode 100644
index 000000000..310899adc
--- /dev/null
+++ b/components/service/fwu/test/ref_scenarios/update_fmp_tests.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <cassert>
+#include <cstring>
+#include <vector>
+
+#include "common/uuid/uuid.h"
+#include "protocols/service/fwu/packed-c/fwu_proto.h"
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+
+#define EFI_BUFFER_TOO_SMALL ((int32_t)5)
+#define EFI_SUCCESS ((int32_t)0)
+
+//*************************************************************
+// EFI_FIRMWARE_IMAGE_DESCRIPTOR
+//*************************************************************
+typedef struct {
+ uint8_t ImageIndex;
+ struct uuid_octets ImageTypeId;
+ uint64_t ImageId;
+ char16_t *ImageIdName;
+ uint32_t Version;
+ char16_t *VersionName;
+ uint64_t Size;
+ uint64_t AttributesSupported;
+ uint64_t AttributesSetting;
+ uint64_t Compatibilities;
+ //Introduced with DescriptorVersion 2+
+ uint32_t LowestSupportedImageVersion;
+ //Introduced with DescriptorVersion 3+
+ uint32_t LastAttemptVersion;
+ uint32_t LastAttemptStatus;
+ uint64_t HardwareInstance;
+} EFI_FIRMWARE_IMAGE_DESCRIPTOR;
+
+struct fmp {
+ explicit fmp(fwu_client *m_fwu_client)
+ : client(m_fwu_client)
+ , is_staging(false)
+ , payload_max_size(0)
+ , img_info(NULL)
+ , num_images(0)
+
+ {
+ parse_img_directory();
+ }
+
+ ~fmp()
+ {
+ if (img_info)
+ delete[] img_info;
+ }
+
+ int get_image_info(uint64_t *ImageInfoSize, EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ uint32_t *DescriptorVersion, uint8_t *DescriptorCount,
+ uint64_t *DescriptorSize, uint32_t *PackageVersion,
+ char16_t **PackageVersionName)
+ {
+ const uint64_t img_info_size = num_images * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR);
+ if (img_info_size > *ImageInfoSize) {
+ *ImageInfoSize = img_info_size;
+
+ return -EFI_BUFFER_TOO_SMALL;
+ }
+
+ memcpy(ImageInfo, img_info, *ImageInfoSize);
+
+ *DescriptorVersion = 3;
+ *DescriptorCount = num_images;
+ *DescriptorSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR);
+
+ // PackageVersion 0xFFFFFFFF means that package version
+ // is not supported. See UEFI specification.
+ *PackageVersion = 0xFFFFFFFF;
+
+ return EFI_SUCCESS;
+ };
+
+ int set_image(uint8_t ImageIndex, const void *Image, uint64_t ImageSize,
+ const void *VendorCode, void *Progress, char16_t **AbortReason)
+ {
+ int status = 0;
+ uint32_t stream_handle = 0;
+
+ struct uuid_octets *uuid = &(img_info[ImageIndex].ImageTypeId);
+
+ if (!is_staging) {
+ status = client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ is_staging = true;
+ }
+
+ status = client->open(uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = client->write_stream(stream_handle, static_cast<const uint8_t *>(Image),
+ ImageSize);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ return 0;
+ };
+
+private:
+ int parse_img_directory()
+ {
+ int status = 0;
+ uint32_t stream_handle = 0;
+ size_t reported_total_len = 0;
+ struct uuid_octets uuid;
+
+ struct ts_fwu_image_directory *img_dir = NULL;
+
+ size_t data_len_read = 0;
+ int num_img = 0;
+
+ assert(img_info == NULL);
+
+ uuid_guid_octets_from_canonical(&uuid, FWU_DIRECTORY_CANONICAL_UUID);
+
+ status = client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ // Determine the size of the FW directory without reading any info.
+ status = client->read_stream(stream_handle, NULL, 0, &data_len_read,
+ &reported_total_len);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ // Close and reopen the firmware directory stream
+ // to reset the read seek.
+ status = client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ status = client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ img_dir = (ts_fwu_image_directory *)new uint8_t[reported_total_len];
+
+ // Read the firmware directory info into img_dir.
+ status = client->read_stream(stream_handle, reinterpret_cast<uint8_t *>(img_dir),
+ reported_total_len, &data_len_read,
+ &reported_total_len);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ LONGS_EQUAL(data_len_read, reported_total_len);
+
+ status = client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ num_img = img_dir->num_images;
+
+ // Translate the data from each entry in the img directory into the img
+ // info array.
+ img_info = (EFI_FIRMWARE_IMAGE_DESCRIPTOR
+ *)new uint8_t[num_img * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR)];
+
+ for (int idx = 0; idx < num_img; idx++) {
+ img_info[idx].ImageIndex = idx;
+ memcpy(img_info[idx].ImageTypeId.octets,
+ img_dir->img_info_entry[idx].img_type_uuid, UUID_OCTETS_LEN);
+ img_info[idx].ImageId = idx;
+ img_info[idx].ImageIdName = NULL;
+ img_info[idx].Version = img_dir->img_info_entry[idx].img_version;
+ img_info[idx].VersionName = NULL;
+ img_info[idx].Size = img_dir->img_info_entry[idx].img_max_size;
+ img_info[idx].AttributesSupported = 0;
+ img_info[idx].AttributesSetting = 0;
+ img_info[idx].Compatibilities = 0;
+ img_info[idx].LowestSupportedImageVersion = 0;
+ img_info[idx].LastAttemptVersion = 0;
+ img_info[idx].LastAttemptStatus = 0;
+ img_info[idx].HardwareInstance = 0;
+ }
+
+ num_images = num_img;
+
+ delete[] img_dir;
+ return status;
+ }
+
+ fwu_client *client;
+ bool is_staging;
+
+ int payload_max_size;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *img_info;
+ uint32_t num_images;
+};
+
+/*
+ * Tests that perform a range of normal update scenarios
+ */
+TEST_GROUP(FwuUpdateFmpTests)
+{
+ void setup()
+ {
+ m_dut = NULL;
+ m_fwu_client = NULL;
+ m_fmp_protocol = NULL;
+ }
+
+ void teardown()
+ {
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+
+ delete m_dut;
+ m_dut = NULL;
+
+ delete m_fmp_protocol;
+ m_fmp_protocol = NULL;
+ }
+
+ fwu_dut *m_dut;
+ fwu_client *m_fwu_client;
+ fmp *m_fmp_protocol;
+};
+
+TEST(FwuUpdateFmpTests, wholeFmpFlow)
+{
+ struct uuid_octets uuid;
+
+ uint64_t ImageInfoSize;
+ uint32_t DescriptorVersion;
+ uint8_t DescriptorCount;
+ uint64_t DescriptorSize;
+ uint32_t PackageVersion;
+ int status;
+
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *img_info = NULL;
+
+ // Create a FW Store with two firmware images.
+ m_dut = fwu_dut_factory::create(1, false);
+ m_fwu_client = m_dut->create_fwu_client();
+
+ assert(m_fwu_client != NULL);
+
+ // Generate the images to be installed.
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data);
+
+ // System start
+ m_dut->boot();
+
+ // Obtain the image_type_guid -- emulate the guid from the payload in an FMP capsule.
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+
+ m_fmp_protocol = new fmp(m_fwu_client);
+
+ ImageInfoSize = 0;
+
+ // First call to fmp.get_image_info obtains the required size.
+ m_fmp_protocol->get_image_info(&ImageInfoSize, img_info, &DescriptorVersion,
+ &DescriptorCount, &DescriptorSize, &PackageVersion, NULL);
+
+ img_info = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)new uint8_t[ImageInfoSize];
+
+ m_fmp_protocol->get_image_info(&ImageInfoSize, img_info, &DescriptorVersion,
+ &DescriptorCount, &DescriptorSize, &PackageVersion, NULL);
+
+ // Iterate over all the image descriptors returned by get_img_info
+ // to obtain the ImageId.
+ for (int idx = 0; idx < DescriptorCount; idx++) {
+ if (uuid_is_equal(img_info[idx].ImageTypeId.octets, uuid.octets)) {
+ uint8_t img_idx = img_info[idx].ImageIndex;
+
+ m_fmp_protocol->set_image(img_idx, image_data.data(), image_data.size(),
+ NULL, NULL, NULL);
+ break;
+ }
+ }
+
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ delete[] img_info;
+}
diff --git a/components/service/fwu/test/ref_scenarios/update_scenario_tests.cpp b/components/service/fwu/test/ref_scenarios/update_scenario_tests.cpp
new file mode 100644
index 000000000..b5c834109
--- /dev/null
+++ b/components/service/fwu/test/ref_scenarios/update_scenario_tests.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <vector>
+
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+
+/*
+ * Tests that perform a range of normal update scenarios
+ */
+TEST_GROUP(FwuUpdateScenarioTests)
+{
+ void setup()
+ {
+ m_dut = NULL;
+ m_fwu_client = NULL;
+ m_metadata_checker = NULL;
+ }
+
+ void teardown()
+ {
+ delete m_metadata_checker;
+ m_metadata_checker = NULL;
+
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+
+ delete m_dut;
+ m_dut = NULL;
+ }
+
+ fwu_dut *m_dut;
+ metadata_checker *m_metadata_checker;
+ fwu_client *m_fwu_client;
+};
+
+TEST(FwuUpdateScenarioTests, wholeFirmwareUpdateFlow)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Performs an update flow where firmware for a device with a
+ * single location is updated using a whole firmware image.
+ */
+ m_dut = fwu_dut_factory::create(1, false);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_metadata_checker = m_dut->create_metadata_checker();
+
+ m_dut->boot();
+
+ /* Check assumptions about the first boot. This represents the fresh out
+ * of the factory state of the device where no updates have ever been
+ * performed,
+ */
+ struct boot_info boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Note the pre-update bank index */
+ unsigned int pre_update_bank_index = boot_info.boot_index;
+
+ /* Perform staging steps where a single image is installed */
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ std::vector<uint8_t> image_data;
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_to_activate(boot_info.boot_index);
+
+ /* Reboot to activate the update */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Check the metadata after the reboot to activate the update */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_trial(boot_info.boot_index);
+
+ /* Accept the update. Because the DUT was configured with a single updatable
+ * image, only a single image needs to be accepted to complete the update
+ * transaction.
+ */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->accept(&uuid);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* The FWU metadata should now reflect the post update state */
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* The update agent should also have transitioned from the trial state.
+ * Confirm this trying an operation that's only permitted in the trial state.
+ */
+ status = m_fwu_client->accept(&uuid);
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Reboot and expect the update to be active */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_regular(boot_info.boot_index);
+ CHECK_TRUE(boot_info.boot_index != pre_update_bank_index);
+}
+
+TEST(FwuUpdateScenarioTests, partialFirmwareUpdateFlow)
+{
+ int status = 0;
+ struct uuid_octets uuid;
+ uint32_t stream_handle = 0;
+
+ /* Performs an update flow where firmware for a device with
+ * multiple firmware locations is updated with a partial update
+ * that only updates a subset of locations. The expectation is
+ * that locations that have not been updated will use the current
+ * version of firmware for the location.
+ */
+ m_dut = fwu_dut_factory::create(3, true);
+ m_fwu_client = m_dut->create_fwu_client();
+ m_metadata_checker = m_dut->create_metadata_checker();
+
+ m_dut->boot();
+
+ /* Check state on first boot */
+ struct boot_info boot_info = m_dut->get_boot_info();
+ UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* Note the pre-update bank index */
+ unsigned int pre_update_bank_index = boot_info.boot_index;
+
+ /* Perform staging steps where multiple images are installed */
+ std::vector<uint8_t> image_data;
+ status = m_fwu_client->begin_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
+
+ /* Install whole image for location 0 */
+ m_dut->whole_volume_image_type_uuid(0, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Accept on commit. No need to accept during trial */
+ status = m_fwu_client->commit(stream_handle, true);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Install whole image for location 1 */
+ m_dut->whole_volume_image_type_uuid(1, &uuid);
+ status = m_fwu_client->open(&uuid, &stream_handle);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ m_dut->generate_image_data(&image_data);
+
+ status = m_fwu_client->write_stream(stream_handle,
+ reinterpret_cast<const uint8_t *>(image_data.data()),
+ image_data.size());
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ status = m_fwu_client->commit(stream_handle, false);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* Don't update location 2 */
+
+ /* End staging */
+ status = m_fwu_client->end_staging();
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+ m_metadata_checker->check_ready_to_activate(boot_info.boot_index);
+
+ /* Reboot to activate the update */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ /* Check the metadata after the reboot to activate the update */
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_trial(boot_info.boot_index);
+
+ /* Accept the update. Image for location 0 was accepted on commit.
+ * Image 2 wasn't updated so it should have been copied as accepted
+ * so only image 1 needs to be accepted.
+ */
+ m_dut->whole_volume_image_type_uuid(1, &uuid);
+ status = m_fwu_client->accept(&uuid);
+ LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
+
+ /* The FWU metadata should now reflect the post update state */
+ m_metadata_checker->check_regular(boot_info.boot_index);
+
+ /* The update agent should also have transitioned from the trial state. */
+ status = m_fwu_client->accept(&uuid);
+ LONGS_EQUAL(FWU_STATUS_DENIED, status);
+
+ /* Reboot and expect the update to be active */
+ m_dut->shutdown();
+ m_dut->boot();
+
+ boot_info = m_dut->get_boot_info();
+ m_metadata_checker->check_regular(boot_info.boot_index);
+ CHECK_TRUE(boot_info.boot_index != pre_update_bank_index);
+}
diff --git a/components/service/fwu/test/service/component.cmake b/components/service/fwu/test/service/component.cmake
new file mode 100644
index 000000000..4cc151e8f
--- /dev/null
+++ b/components/service/fwu/test/service/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_service_tests.cpp"
+ )
diff --git a/components/service/fwu/test/service/fwu_service_tests.cpp b/components/service/fwu/test/service/fwu_service_tests.cpp
new file mode 100644
index 000000000..0476d9258
--- /dev/null
+++ b/components/service/fwu/test/service/fwu_service_tests.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <vector>
+
+#include "protocols/service/fwu/packed-c/status.h"
+#include "service/fwu/test/fwu_dut/fwu_dut.h"
+#include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
+#include "service/fwu/test/image_directory_checker/image_directory_checker.h"
+
+/*
+ * FWU service level tests that can be run with other service level tests.
+ * Because these tests may be run on the device-under-test, update activation
+ * scenarios that rely on a shutdown and restart are not included in tests.
+ * These tests are mainly concerned with checking that the service provider
+ * is reachable and is responding to requests made by a client.
+ */
+TEST_GROUP(FwuServiceTests)
+{
+ void setup()
+ {
+ m_dut = NULL;
+ m_fwu_client = NULL;
+ m_metadata_checker = NULL;
+
+ m_dut = fwu_dut_factory::create(1, false);
+ CHECK_TRUE(m_dut);
+ }
+
+ void teardown()
+ {
+ delete m_metadata_checker;
+ m_metadata_checker = NULL;
+
+ delete m_fwu_client;
+ m_fwu_client = NULL;
+
+ delete m_dut;
+ m_dut = NULL;
+ }
+
+ fwu_dut *m_dut;
+ metadata_checker *m_metadata_checker;
+ fwu_client *m_fwu_client;
+};
+
+TEST(FwuServiceTests, checkImgDirAccess)
+{
+ m_fwu_client = m_dut->create_fwu_client();
+ CHECK_TRUE(m_fwu_client);
+
+ m_dut->boot();
+
+ image_directory_checker img_dir_checker;
+
+ int status = img_dir_checker.fetch_image_directory(m_fwu_client);
+ LONGS_EQUAL(0, status);
+
+ CHECK_TRUE(img_dir_checker.num_images() > 0);
+}
+
+TEST(FwuServiceTests, checkMetadataAccess)
+{
+ m_metadata_checker = m_dut->create_metadata_checker();
+ CHECK_TRUE(m_metadata_checker);
+
+ m_dut->boot();
+
+ uint32_t active_index;
+ uint32_t previous_active_index;
+
+ m_metadata_checker->get_active_indices(&active_index, &previous_active_index);
+ m_metadata_checker->check_regular(active_index);
+} \ No newline at end of file
diff --git a/components/service/locator/interface/component.cmake b/components/service/locator/interface/component.cmake
index b5aefa371..84a4d7562 100644
--- a/components/service/locator/interface/component.cmake
+++ b/components/service/locator/interface/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,10 +8,11 @@ if (NOT DEFINED TGT)
message(FATAL_ERROR "mandatory parameter TGT is not defined.")
endif()
-set_property(TARGET ${TGT} PROPERTY SERVICE_LOCATOR_PUBLIC_HEADER_FILES
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
"${CMAKE_CURRENT_LIST_DIR}/service_locator.h"
)
target_include_directories(${TGT} PUBLIC
- "${CMAKE_CURRENT_LIST_DIR}"
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>"
+ "$<INSTALL_INTERFACE:${TS_ENV}/include>"
)
diff --git a/components/service/locator/interface/service_locator.h b/components/service/locator/interface/service_locator.h
index 1fba4530e..87f1f0dc0 100644
--- a/components/service/locator/interface/service_locator.h
+++ b/components/service/locator/interface/service_locator.h
@@ -7,7 +7,7 @@
#ifndef SERVICE_LOCATOR_H
#define SERVICE_LOCATOR_H
-#include <rpc_caller.h>
+#include "components/rpc/common/caller/rpc_caller_session.h"
/*
* The service_locator puplic interface may be exported as a public interface to
@@ -32,7 +32,6 @@ extern "C" {
* client code may be reused accross different service deployment scenarios.
*/
struct service_location_strategy;
-typedef void* rpc_session_handle;
/*
* Initialises the singleton service locator. Must be called once
@@ -64,7 +63,7 @@ void service_locator_register_strategy(const struct service_location_strategy *s
* the client should call the relinquish method. Returns NULL
* if no service is located that corresponds to the service name.
*/
-SERVICE_LOCATOR_EXPORTED struct service_context *service_locator_query(const char *sn, int *status);
+SERVICE_LOCATOR_EXPORTED struct service_context *service_locator_query(const char *sn);
/*
* The service_context struct represents a service instance to a client
@@ -74,11 +73,11 @@ SERVICE_LOCATOR_EXPORTED struct service_context *service_locator_query(const cha
*/
struct service_context
{
- void *context;
+ void *context;
- rpc_session_handle (*open)(void *context, struct rpc_caller **caller);
- void (*close)(void *context, rpc_session_handle session_handle);
- void (*relinquish)(void *context);
+ struct rpc_caller_session *(*open)(void *context);
+ void (*close)(void *context, struct rpc_caller_session *session);
+ void (*relinquish)(void *context);
};
/*
@@ -88,7 +87,7 @@ struct service_context
*/
struct service_location_strategy
{
- struct service_context *(*query)(const char *sn, int *status);
+ struct service_context *(*query)(const char *sn);
};
/*
@@ -96,12 +95,12 @@ struct service_location_strategy
* service_context. The parameter encoding scheme that the client
* intends to use for serializing RPC parameters must be specified.
*/
-SERVICE_LOCATOR_EXPORTED rpc_session_handle service_context_open(struct service_context *s, uint32_t encoding, struct rpc_caller **caller);
+SERVICE_LOCATOR_EXPORTED struct rpc_caller_session *service_context_open(struct service_context *s);
/*
* Close an RPC session.
*/
-SERVICE_LOCATOR_EXPORTED void service_context_close(struct service_context *s, rpc_session_handle session_handle);
+SERVICE_LOCATOR_EXPORTED void service_context_close(struct service_context *s, struct rpc_caller_session *session_handle);
/*
* Called by a client when it has finished using a service context.
diff --git a/components/service/locator/linux/ffa/linuxffa_location_strategy.c b/components/service/locator/linux/ffa/linuxffa_location_strategy.c
index a6ec465bb..a90487635 100644
--- a/components/service/locator/linux/ffa/linuxffa_location_strategy.c
+++ b/components/service/locator/linux/ffa/linuxffa_location_strategy.c
@@ -1,204 +1,81 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "linuxffa_location_strategy.h"
#include "linuxffa_service_context.h"
-#include <common/uuid/uuid.h>
-#include <service/locator/service_name.h>
-#include <rpc/ffarpc/caller/linux/ffarpc_caller.h>
-#include <deployments/se-proxy/se_proxy_interfaces.h>
+#include "common/uuid/uuid.h"
+#include "service/locator/service_name.h"
+#include "components/service/attestation/provider/attestation_uuid.h"
+#include "components/service/block_storage/provider/block_storage_uuid.h"
+#include "components/service/crypto/provider/crypto_uuid.h"
+#include "components/service/fwu/provider/fwu_uuid.h"
+#include "components/service/rpmb/provider/rpmb_uuid.h"
+#include "components/service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
+#include "components/service/test_runner/provider/test_runner_uuid.h"
#include <stddef.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
-/*
- * There is the potential for there to be alternative deployment possibilities
- * for a service instance. This will depend on deployment decisions such as
- * running one service instance per SP, or multiple services per SP. The FFA
- * location strategy accommodates this by allowing for more than one suggestion
- * for a service to partition mapping.
- */
-#define MAX_PARTITION_SUGGESTIONS (4)
-/*
- * The maximum number of partition instances, identified by a particular UUID,
- * that may be discovered.
- */
-#define MAX_PARTITION_INSTANCES (4)
+static struct service_context *query(const char *sn);
+static const struct rpc_uuid *suggest_ts_service_uuids(const char *sn);
-/*
- * Structure to specify the location of a service endpoint reachable via FFA.
- */
-struct ffa_service_location
-{
- struct uuid_canonical uuid;
- uint16_t iface_id;
-};
-
-
-static struct service_context *query(const char *sn,
- int *status);
-static size_t suggest_tf_org_partition_uuids(const char *sn,
- struct ffa_service_location *candidates, size_t candidate_limit);
-static size_t use_ffa_partition_uuid(const char *sn,
- struct ffa_service_location *candidates, size_t candidate_limit);
-static bool discover_partition(const char *sn,
- struct uuid_canonical *uuid, const char *dev_path, uint16_t *partition_id);
-
-const struct service_location_strategy *linuxffa_location_strategy(void)
+const struct service_location_strategy *linux_ts_location_strategy(void)
{
static const struct service_location_strategy strategy = { query };
return &strategy;
}
-static struct service_context *query(const char *sn, int *status)
+static struct service_context *query(const char *sn)
{
- struct service_context *result = NULL;
- struct ffa_service_location candidate_locations[MAX_PARTITION_SUGGESTIONS];
- size_t num_suggestons = 0;
- size_t suggeston_index;
+ const struct rpc_uuid *service_uuid = NULL;
/* Determine one or more candidate partition UUIDs from the specified service name. */
- if (sn_check_authority(sn, "trustedfirmware.org")) {
- num_suggestons =
- suggest_tf_org_partition_uuids(sn, candidate_locations, MAX_PARTITION_SUGGESTIONS);
- }
- else if (sn_check_authority(sn, "ffa")) {
- num_suggestons =
- use_ffa_partition_uuid(sn, candidate_locations, MAX_PARTITION_SUGGESTIONS);
- }
-
- /* Attempt to discover suitable partitions */
- for (suggeston_index = 0; suggeston_index < num_suggestons; ++suggeston_index) {
+ if (!sn_check_authority(sn, "trustedfirmware.org"))
+ return NULL;
- uint16_t partition_id;
- const char *dev_path = "/sys/kernel/debug/arm_ffa_user";
+ service_uuid = suggest_ts_service_uuids(sn);
+ if (!service_uuid)
+ return NULL;
- if (discover_partition(sn, &candidate_locations[suggeston_index].uuid,
- dev_path, &partition_id)) {
-
- struct linuxffa_service_context *new_context =
- linuxffa_service_context_create(dev_path,
- partition_id, candidate_locations[suggeston_index].iface_id);
-
- if (new_context) result = &new_context->service_context;
- break;
- }
- }
-
- return result;
+ return (struct service_context *)linux_ts_service_context_create(service_uuid);
}
/*
- * Returns a list of partition UUIDs and interface IDs to identify partitions that
- * could potentially host the requested service. This mapping is based trustedfirmware.org
- * ffa partition UUIDs. There may be multiple UUIDs because of different depeloyment decisions
- * such as dedicated SP, SP hosting multple services.
+ * Returns a list of service UUIDs to identify partitions that could potentially host the requested
+ * service. This mapping is based trustedfirmware.org service UUIDs. There may be multiple UUIDs
+ * because of different deployment decisions such as dedicated SP, SP hosting multiple services.
*/
-static size_t suggest_tf_org_partition_uuids(const char *sn,
- struct ffa_service_location *candidates, size_t candidate_limit)
+static const struct rpc_uuid *suggest_ts_service_uuids(const char *sn)
{
- const struct service_to_uuid
+ static const struct service_to_uuid
{
const char *service;
- const char *uuid;
- uint16_t iface_id;
+ struct rpc_uuid uuid;
}
partition_lookup[] =
{
- /* Services in dedicated SPs */
- {"crypto", "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0", 0},
- {"internal-trusted-storage", "dc1eef48-b17a-4ccf-ac8b-dfcff7711b14", 0},
- {"protected-storage", "751bf801-3dde-4768-a514-0f10aeed1790", 0},
- {"test-runner", "33c75baf-ac6a-4fe4-8ac7-e9909bee2d17", 0},
- {"attestation", "a1baf155-8876-4695-8f7c-54955e8db974", 0},
-
- /* Secure Enclave proxy accessed services */
- {"crypto", "46bb39d1-b4d9-45b5-88ff-040027dab249", SE_PROXY_INTERFACE_ID_CRYPTO},
- {"internal-trusted-storage", "46bb39d1-b4d9-45b5-88ff-040027dab249", SE_PROXY_INTERFACE_ID_ITS},
- {"protected-storage", "46bb39d1-b4d9-45b5-88ff-040027dab249", SE_PROXY_INTERFACE_ID_PS},
- {"attestation", "46bb39d1-b4d9-45b5-88ff-040027dab249", SE_PROXY_INTERFACE_ID_ATTEST},
- {NULL, NULL, 0}
+ {"crypto-protobuf", {.uuid = TS_PSA_CRYPTO_PROTOBUF_SERVICE_UUID}},
+ {"crypto", {.uuid = TS_PSA_CRYPTO_SERVICE_UUID}},
+ {"internal-trusted-storage", {.uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID}},
+ {"protected-storage", {.uuid = TS_PSA_PROTECTED_STORAGE_UUID}},
+ {"test-runner", {.uuid = TS_TEST_RUNNER_SERVICE_UUID}},
+ {"attestation", {.uuid = TS_PSA_ATTESTATION_SERVICE_UUID}},
+ {"block-storage", {.uuid = TS_BLOCK_STORAGE_SERVICE_UUID}},
+ {"fwu", {.uuid = TS_FWU_SERVICE_UUID}},
+ {"rpmb", {.uuid = TS_RPMB_SERVICE_UUID}},
+ {NULL, {.uuid = {0}}}
};
- const struct service_to_uuid *entry = &partition_lookup[0];
- size_t num_suggestions = 0;
-
- while (entry->service && (num_suggestions < candidate_limit)) {
-
- if (sn_check_service(sn, entry->service)) {
-
- memcpy(candidates[num_suggestions].uuid.characters, entry->uuid,
- UUID_CANONICAL_FORM_LEN + 1);
-
- candidates[num_suggestions].iface_id = entry->iface_id;
-
- ++num_suggestions;
- }
-
- ++entry;
- }
-
- return num_suggestions;
-}
-
-/*
- * When an ffa service name where the service field is an explicit UUID is used, the UUID
- * is used directly for partition discovery.
- */
-static size_t use_ffa_partition_uuid(const char *sn,
- struct ffa_service_location *candidates, size_t candidate_limit)
-{
- size_t num_suggestions = 0;
-
- if ((num_suggestions < candidate_limit) &&
- (sn_read_service(sn, candidates[num_suggestions].uuid.characters,
- UUID_CANONICAL_FORM_LEN + 1) == UUID_CANONICAL_FORM_LEN)) {
+ const struct service_to_uuid *entry = NULL;
- candidates[num_suggestions].iface_id = 0;
-
- ++num_suggestions;
- }
-
- return num_suggestions;
-}
-
-/*
- * Attempt to discover the partition that hosts the requested service instance.
- */
-static bool discover_partition(const char *sn,
- struct uuid_canonical *uuid, const char *dev_path, uint16_t *partition_id)
-{
- bool discovered = false;
-
- if (uuid_is_valid(uuid->characters) == UUID_CANONICAL_FORM_LEN) {
-
- struct ffarpc_caller ffarpc_caller;
- unsigned int required_instance = sn_get_service_instance(sn);
-
- if (!ffarpc_caller_check_version())
- return false;
-
- ffarpc_caller_init(&ffarpc_caller, dev_path);
-
- uint16_t discovered_partitions[MAX_PARTITION_INSTANCES];
- size_t discovered_count;
-
- discovered_count = ffarpc_caller_discover(&ffarpc_caller, uuid,
- discovered_partitions, MAX_PARTITION_INSTANCES);
-
- if ((discovered_count > 0) && (required_instance < discovered_count)) {
-
- *partition_id = discovered_partitions[required_instance];
- discovered = true;
- }
-
- ffarpc_caller_deinit(&ffarpc_caller);
- }
+ for (entry = &partition_lookup[0]; entry->service != NULL; entry++)
+ if (sn_check_service(sn, entry->service))
+ return &entry->uuid;
- return discovered;
+ return NULL;
}
diff --git a/components/service/locator/linux/ffa/linuxffa_location_strategy.h b/components/service/locator/linux/ffa/linuxffa_location_strategy.h
index 6bb7eeb6e..da8260c05 100644
--- a/components/service/locator/linux/ffa/linuxffa_location_strategy.h
+++ b/components/service/locator/linux/ffa/linuxffa_location_strategy.h
@@ -7,7 +7,7 @@
#ifndef LINUXFFA_LOCATION_STRATEGY_H
#define LINUXFFA_LOCATION_STRATEGY_H
-#include <service_locator.h>
+#include "service_locator.h"
#ifdef __cplusplus
extern "C" {
@@ -15,10 +15,10 @@ extern "C" {
/*
* Returns a service_location_strategy for locating a service instance
- * hosted in a secure partition, accessed using FFA from Linux userspace.
- * Relies on an FFA Linux kernel driver.
+ * hosted in a secure partition, accessed using TS RPC from Linux userspace.
+ * Relies on an TS Linux kernel driver.
*/
-const struct service_location_strategy *linuxffa_location_strategy(void);
+const struct service_location_strategy *linux_ts_location_strategy(void);
#ifdef __cplusplus
}
diff --git a/components/service/locator/linux/ffa/linuxffa_service_context.c b/components/service/locator/linux/ffa/linuxffa_service_context.c
index ae558412c..ad6ebc290 100644
--- a/components/service/locator/linux/ffa/linuxffa_service_context.c
+++ b/components/service/locator/linux/ffa/linuxffa_service_context.c
@@ -1,84 +1,98 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "linuxffa_service_context.h"
-#include <rpc/ffarpc/caller/linux/ffarpc_caller.h>
+#include "components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.h"
#include <stdlib.h>
+#include <string.h>
+
+struct linux_ts_service_context
+{
+ struct service_context service_context;
+ struct rpc_caller_interface caller;
+ struct rpc_uuid service_uuid;
+};
/* Concrete service_context methods */
-static rpc_session_handle linuxffa_service_context_open(void *context, struct rpc_caller **caller);
-static void linuxffa_service_context_close(void *context, rpc_session_handle session_handle);
-static void linuxffa_service_context_relinquish(void *context);
+static struct rpc_caller_session *linux_ts_service_context_open(void *context);
+static void linux_ts_service_context_close(void *context, struct rpc_caller_session *session);
+static void linux_ts_service_context_relinquish(void *context);
-struct linuxffa_service_context *linuxffa_service_context_create(const char *dev_path,
- uint16_t partition_id, uint16_t iface_id)
+struct linux_ts_service_context *linux_ts_service_context_create(const struct rpc_uuid *service_uuid)
+
{
- struct linuxffa_service_context *new_context =
- (struct linuxffa_service_context*)malloc(sizeof(struct linuxffa_service_context));
+ struct linux_ts_service_context *new_context = NULL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
- if (new_context) {
- new_context->ffa_dev_path = dev_path;
- new_context->partition_id = partition_id;
- new_context->iface_id = iface_id;
+ if (!service_uuid)
+ return NULL;
- new_context->service_context.context = new_context;
- new_context->service_context.open = linuxffa_service_context_open;
- new_context->service_context.close = linuxffa_service_context_close;
- new_context->service_context.relinquish = linuxffa_service_context_relinquish;
- }
+ new_context = (struct linux_ts_service_context *)
+ calloc(1, sizeof(struct linux_ts_service_context));
+ if (!new_context)
+ return NULL;
- return new_context;
-}
+ rpc_status = ts_rpc_caller_linux_init(&new_context->caller);
+ if (rpc_status != RPC_SUCCESS) {
+ free(new_context);
+ return NULL;
+ }
-static rpc_session_handle linuxffa_service_context_open(void *context, struct rpc_caller **caller)
-{
- struct linuxffa_service_context *this_context = (struct linuxffa_service_context*)context;
- rpc_session_handle session_handle = NULL;
- struct ffarpc_caller *ffarpc_caller =
- (struct ffarpc_caller*)malloc(sizeof(struct ffarpc_caller));
-
- if (ffarpc_caller) {
-
- int status;
- *caller = ffarpc_caller_init(ffarpc_caller, this_context->ffa_dev_path);
- status = ffarpc_caller_open(ffarpc_caller,
- this_context->partition_id, this_context->iface_id);
-
- if (status == 0) {
- /* Successfully opened session */
- session_handle = ffarpc_caller;
- }
- else {
- /* Failed to open session */
- ffarpc_caller_close(ffarpc_caller);
- ffarpc_caller_deinit(ffarpc_caller);
- free(ffarpc_caller);
- }
- }
-
- return session_handle;
+ memcpy(&new_context->service_uuid, service_uuid, sizeof(new_context->service_uuid));
+
+ new_context->service_context.context = new_context;
+ new_context->service_context.open = linux_ts_service_context_open;
+ new_context->service_context.close = linux_ts_service_context_close;
+ new_context->service_context.relinquish = linux_ts_service_context_relinquish;
+
+ return new_context;
}
-static void linuxffa_service_context_close(void *context, rpc_session_handle session_handle)
+static struct rpc_caller_session *linux_ts_service_context_open(void *context)
{
- struct ffarpc_caller *ffarpc_caller = (struct ffarpc_caller*)session_handle;
+ struct linux_ts_service_context *this_context = (struct linux_ts_service_context *)context;
+ struct rpc_caller_session *session = NULL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
- (void)context;
+ if (!context)
+ return NULL;
- if (ffarpc_caller) {
+ session = (struct rpc_caller_session *)calloc(1, sizeof(struct rpc_caller_session));
+ if (!session)
+ return NULL;
- ffarpc_caller_close(ffarpc_caller);
- ffarpc_caller_deinit(ffarpc_caller);
- free(ffarpc_caller);
- }
+ rpc_status = rpc_caller_session_find_and_open(session, &this_context->caller,
+ &this_context->service_uuid, 8192);
+ if (rpc_status != RPC_SUCCESS) {
+ free(session);
+ return NULL;
+ }
+
+ return session;
}
-static void linuxffa_service_context_relinquish(void *context)
+static void linux_ts_service_context_close(void *context, struct rpc_caller_session *session)
{
- struct linuxffa_service_context *this_context = (struct linuxffa_service_context*)context;
- free(this_context);
+ (void)context;
+
+ if (!session)
+ return;
+
+ rpc_caller_session_close(session);
+ free(session);
}
+
+static void linux_ts_service_context_relinquish(void *context)
+{
+ struct linux_ts_service_context *this_context = (struct linux_ts_service_context *)context;
+
+ if (!context)
+ return;
+
+ ts_rpc_caller_linux_deinit(&this_context->caller);
+ free(context);
+} \ No newline at end of file
diff --git a/components/service/locator/linux/ffa/linuxffa_service_context.h b/components/service/locator/linux/ffa/linuxffa_service_context.h
index d2e6753c7..196f5345a 100644
--- a/components/service/locator/linux/ffa/linuxffa_service_context.h
+++ b/components/service/locator/linux/ffa/linuxffa_service_context.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,7 +7,7 @@
#ifndef LINUXFFA_SERVICE_CONTEXT_H
#define LINUXFFA_SERVICE_CONTEXT_H
-#include <service_locator.h>
+#include "service_locator.h"
#ifdef __cplusplus
extern "C" {
@@ -18,20 +18,13 @@ extern "C" {
* a partition, accessed via FFA. This service_context is suitable
* for use by client applications running in Linux userspace.
*/
-struct linuxffa_service_context
-{
- struct service_context service_context;
- const char *ffa_dev_path;
- uint16_t partition_id;
- uint16_t iface_id;
-};
+struct linux_ts_service_context;
/*
- * Factory method to create a service context associated with theh specified
- * partition id and RPC interface instance.
+ * Factory method to create a service context associated with the specified
+ * service UUID.
*/
-struct linuxffa_service_context *linuxffa_service_context_create(const char *dev_path,
- uint16_t partition_id, uint16_t iface_id);
+struct linux_ts_service_context *linux_ts_service_context_create(const struct rpc_uuid *service_uuid);
#ifdef __cplusplus
}
diff --git a/components/service/locator/linux/linux_env.c b/components/service/locator/linux/linux_env.c
index 4bef3018f..2d920c69a 100644
--- a/components/service/locator/linux/linux_env.c
+++ b/components/service/locator/linux/linux_env.c
@@ -14,6 +14,6 @@ void service_locator_envinit(void)
* Register all service location strategies that could be used
* to locate services from Linux userspace.
*/
- service_locator_register_strategy(linuxffa_location_strategy());
+ service_locator_register_strategy(linux_ts_location_strategy());
service_locator_register_strategy(mm_communicate_location_strategy());
}
diff --git a/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.c b/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.c
index 632c682b7..4c22756ee 100644
--- a/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.c
+++ b/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,8 +12,6 @@
#include <rpc/mm_communicate/caller/linux/mm_communicate_caller.h>
#include <protocols/service/smm_variable/smm_variable_proto.h>
-#define MAX_PARTITION_INSTANCES (1)
-
/* Structure to define the location of an smm service */
struct smm_service_location
{
@@ -36,7 +34,7 @@ bool find_candidate_location(const char *sn, struct smm_service_location *locati
{
{
.service = "smm-variable",
- .uuid = "ed32d533-99e6-4209-9cc0-2d72cdd998a7",
+ .uuid = SMM_VARIABLE_CANONICAL_GUID,
.svc_guid = SMM_VARIABLE_GUID
},
{
@@ -69,59 +67,27 @@ bool find_candidate_location(const char *sn, struct smm_service_location *locati
return found;
}
-bool discover_partition(const char *dev_path, struct smm_service_location *location)
+static struct service_context *query(const char *sn)
{
- bool discovered = false;
-
- if (uuid_is_valid(location->uuid.characters) == UUID_CANONICAL_FORM_LEN) {
-
- struct mm_communicate_caller mm_communicate_caller;
+ struct smm_service_location location = { 0 };
+ struct mm_communicate_service_context *new_context = NULL;
+ static const char *dev_path = "/sys/kernel/debug/arm_ffa_user";
- mm_communicate_caller_init(&mm_communicate_caller, dev_path);
- uint16_t discovered_partitions[MAX_PARTITION_INSTANCES];
- size_t discovered_count;
+ if (!sn_check_authority(sn, "trustedfirmware.org"))
+ return NULL;
- discovered_count = mm_communicate_caller_discover(
- &mm_communicate_caller,
- &location->uuid,
- discovered_partitions,
- MAX_PARTITION_INSTANCES);
+ if (!find_candidate_location(sn, &location))
+ return NULL;
- if (discovered_count > 0) {
-
- location->partition_id = discovered_partitions[0];
- discovered = true;
- }
-
- mm_communicate_caller_deinit(&mm_communicate_caller);
- }
-
- return discovered;
-}
-
-static struct service_context *query(const char *sn, int *status)
-{
- struct service_context *result = NULL;
-
- if (!sn_check_authority(sn, "trustedfirmware.org")) return NULL;
-
- struct smm_service_location location;
- const char *dev_path = "/sys/kernel/debug/arm_ffa_user";
-
- if (find_candidate_location(sn, &location) &&
- discover_partition(dev_path, &location)) {
-
- struct mm_communicate_service_context *new_context =
- mm_communicate_service_context_create(
- dev_path,
- location.partition_id,
- &location.svc_guid);
-
- if (new_context) result = &new_context->service_context;
- }
+ new_context = mm_communicate_service_context_create(
+ dev_path,
+ location.partition_id,
+ &location.svc_guid);
+ if (!new_context)
+ return NULL;
- return result;
+ return &new_context->service_context;
}
const struct service_location_strategy *mm_communicate_location_strategy(void)
diff --git a/components/service/locator/linux/mm_communicate/mm_communicate_service_context.c b/components/service/locator/linux/mm_communicate/mm_communicate_service_context.c
index 7e6330d5f..5573795f3 100644
--- a/components/service/locator/linux/mm_communicate/mm_communicate_service_context.c
+++ b/components/service/locator/linux/mm_communicate/mm_communicate_service_context.c
@@ -1,100 +1,96 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <stdlib.h>
#include <rpc/mm_communicate/caller/linux/mm_communicate_caller.h>
#include "mm_communicate_service_context.h"
+#include <stdlib.h>
+#include <string.h>
/* Concrete service_context methods */
-static rpc_session_handle mm_communicate_service_context_open(void *context,
- struct rpc_caller **caller);
+static struct rpc_caller_session *mm_communicate_service_context_open(void *context);
static void mm_communicate_service_context_close(void *context,
- rpc_session_handle session_handle);
+ struct rpc_caller_session *session_handle);
static void mm_communicate_service_context_relinquish(void *context);
+static void efi_guid_to_rpc_uuid(const EFI_GUID *guid, struct rpc_uuid *uuid)
+{
+ uuid->uuid[0] = (guid->Data1 >> 24) & 0xff;
+ uuid->uuid[1] = (guid->Data1 >> 16) & 0xff;
+ uuid->uuid[2] = (guid->Data1 >> 8) & 0xff;
+ uuid->uuid[3] = guid->Data1 & 0xff;
+ uuid->uuid[4] = (guid->Data2 >> 8) & 0xff;
+ uuid->uuid[5] = guid->Data2 & 0xff;
+ uuid->uuid[6] = (guid->Data3 >> 8) & 0xff;
+ uuid->uuid[7] = guid->Data3 & 0xff;
+ memcpy(&uuid->uuid[8], guid->Data4, sizeof(guid->Data4));
+}
struct mm_communicate_service_context *mm_communicate_service_context_create(
const char *dev_path,
uint16_t partition_id,
const EFI_GUID *svc_guid)
{
- struct mm_communicate_service_context *new_context = (struct mm_communicate_service_context*)
- malloc(sizeof(struct mm_communicate_service_context));
+ struct mm_communicate_service_context *new_context =
+ (struct mm_communicate_service_context*)calloc(1, sizeof(struct mm_communicate_service_context));
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
- if (new_context) {
+ if (!new_context)
+ return NULL;
- new_context->ffa_dev_path = dev_path;
- new_context->partition_id = partition_id;
- new_context->svc_guid = *svc_guid;
-
- new_context->service_context.context = new_context;
- new_context->service_context.open = mm_communicate_service_context_open;
- new_context->service_context.close = mm_communicate_service_context_close;
- new_context->service_context.relinquish = mm_communicate_service_context_relinquish;
+ rpc_status = mm_communicate_caller_init(&new_context->caller, dev_path);
+ if (rpc_status != RPC_SUCCESS) {
+ free(new_context);
+ return NULL;
}
+ new_context->partition_id = partition_id;
+ new_context->svc_guid = *svc_guid;
+
+ new_context->service_context.context = new_context;
+ new_context->service_context.open = mm_communicate_service_context_open;
+ new_context->service_context.close = mm_communicate_service_context_close;
+ new_context->service_context.relinquish = mm_communicate_service_context_relinquish;
+
return new_context;
}
-static rpc_session_handle mm_communicate_service_context_open(
- void *context,
- struct rpc_caller **caller)
+static struct rpc_caller_session *mm_communicate_service_context_open(void *context)
{
struct mm_communicate_service_context *this_context =
(struct mm_communicate_service_context*)context;
+ struct rpc_caller_session *session = (struct rpc_caller_session *)calloc(1, sizeof(struct rpc_caller_session));
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct rpc_uuid service_uuid = { 0 };
- rpc_session_handle session_handle = NULL;
-
- struct mm_communicate_caller *mm_communicate_caller =
- (struct mm_communicate_caller*)malloc(sizeof(struct mm_communicate_caller));
+ if (!session)
+ return NULL;
- if (mm_communicate_caller) {
+ efi_guid_to_rpc_uuid(&this_context->svc_guid, &service_uuid);
- *caller = mm_communicate_caller_init(mm_communicate_caller,
- this_context->ffa_dev_path);
- int status = mm_communicate_caller_open(mm_communicate_caller,
- this_context->partition_id, &this_context->svc_guid);
-
- if (status == 0) {
- /* Successfully opened session */
- session_handle = mm_communicate_caller;
- }
- else {
- /* Failed to open session */
- mm_communicate_caller_close(mm_communicate_caller);
- mm_communicate_caller_deinit(mm_communicate_caller);
- free(mm_communicate_caller);
- }
+ /* The memory size is set to 0 because carveout configuration controls this. */
+ rpc_status = rpc_caller_session_find_and_open(session, &this_context->caller,
+ &service_uuid, 0);
+ if (rpc_status != RPC_SUCCESS) {
+ free(session);
+ return NULL;
}
- return session_handle;
+ return session;
}
-static void mm_communicate_service_context_close(
- void *context,
- rpc_session_handle session_handle)
+static void mm_communicate_service_context_close(void *context, struct rpc_caller_session *session)
{
- struct mm_communicate_caller *mm_communicate_caller =
- (struct mm_communicate_caller*)session_handle;
-
(void)context;
- if (mm_communicate_caller) {
-
- mm_communicate_caller_close(mm_communicate_caller);
- mm_communicate_caller_deinit(mm_communicate_caller);
- free(mm_communicate_caller);
- }
+ rpc_caller_session_close(session);
+ free(session);
}
static void mm_communicate_service_context_relinquish(
void *context)
{
- struct mm_communicate_service_context *this_context =
- (struct mm_communicate_service_context*)context;
-
- free(this_context);
+ free(context);
}
diff --git a/components/service/locator/linux/mm_communicate/mm_communicate_service_context.h b/components/service/locator/linux/mm_communicate/mm_communicate_service_context.h
index 6771c317a..27535ce33 100644
--- a/components/service/locator/linux/mm_communicate/mm_communicate_service_context.h
+++ b/components/service/locator/linux/mm_communicate/mm_communicate_service_context.h
@@ -22,7 +22,7 @@ extern "C" {
struct mm_communicate_service_context
{
struct service_context service_context;
- const char *ffa_dev_path;
+ struct rpc_caller_interface caller;
uint16_t partition_id;
EFI_GUID svc_guid;
};
diff --git a/components/service/locator/remote/restapi/component.cmake b/components/service/locator/remote/restapi/component.cmake
new file mode 100644
index 000000000..5e37d00d7
--- /dev/null
+++ b/components/service/locator/remote/restapi/component.cmake
@@ -0,0 +1,28 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/restapi_env.c"
+ "${CMAKE_CURRENT_LIST_DIR}/restapi_location_strategy.c"
+ "${CMAKE_CURRENT_LIST_DIR}/restapi_service_context.c"
+ )
+
+# Configurable build parameters
+# TS_CFG_REST_API_SERVICE_URL URL for reaching services via REST API
+# TS_CFG_REST_API_REACHABLE_TIMEOUT Timeout in seconds for waiting to reach API
+if(DEFINED TS_CFG_REST_API_SERVICE_URL)
+ target_compile_definitions(${TGT} PRIVATE
+ RESTAPI_LOCATOR_API_URL=${TS_CFG_REST_API_SERVICE_URL})
+endif()
+
+if(DEFINED TS_CFG_REST_API_REACHABLE_TIMEOUT)
+ target_compile_definitions(${TGT} PRIVATE
+ RESTAPI_LOCATOR_MAX_API_WAIT=${TS_CFG_REST_API_REACHABLE_TIMEOUT})
+endif()
diff --git a/components/service/locator/remote/restapi/restapi_env.c b/components/service/locator/remote/restapi/restapi_env.c
new file mode 100644
index 000000000..8e6561f7c
--- /dev/null
+++ b/components/service/locator/remote/restapi/restapi_env.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "restapi_location_strategy.h"
+#include "service_locator.h"
+
+void service_locator_envinit(void)
+{
+ /**
+ * Register service location strategy for reaching services using
+ * the FW Test API or any other REST API that presents a remotely
+ * reachable test interface to a DUT. Call requests are made using
+ * an HTTP based RPC layer.
+ */
+ service_locator_register_strategy(restapi_location_strategy());
+}
diff --git a/components/service/locator/remote/restapi/restapi_location.h b/components/service/locator/remote/restapi/restapi_location.h
new file mode 100644
index 000000000..bd4986fff
--- /dev/null
+++ b/components/service/locator/remote/restapi/restapi_location.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RESTAPI_LOCATION_H
+#define RESTAPI_LOCATION_H
+
+/* The default REST API URL. Can be overridden at build-time if an alterantive
+ * is required.
+ */
+#ifndef RESTAPI_LOCATOR_API_URL
+#define RESTAPI_LOCATOR_API_URL "http://127.0.0.1/api/v1/services/"
+#endif
+
+#endif /* RESTAPI_LOCATION_STRATEGY_H */
diff --git a/components/service/locator/remote/restapi/restapi_location_strategy.c b/components/service/locator/remote/restapi/restapi_location_strategy.c
new file mode 100644
index 000000000..93dcb3f03
--- /dev/null
+++ b/components/service/locator/remote/restapi/restapi_location_strategy.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "restapi_location_strategy.h"
+
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "restapi_location.h"
+#include "restapi_service_context.h"
+#include "rpc/http/caller/http_caller.h"
+#include "service/locator/service_name.h"
+#include "trace.h"
+
+/* Maximum wait for an unresponsive API server. During testing, this period
+ * may need to accommodate the boot time for a device under test.
+ */
+#ifndef RESTAPI_LOCATOR_MAX_API_WAIT
+#define RESTAPI_LOCATOR_MAX_API_WAIT (120)
+#endif
+
+static bool probe_api_server(void)
+{
+ unsigned int seconds_waited = 0;
+
+ do {
+ long http_code = 0;
+
+ if (http_caller_probe(RESTAPI_LOCATOR_API_URL, &http_code))
+ return true;
+
+ /* Failed to reach API or received an error response */
+ if (http_code == 0) {
+ /* It's possible that the device hosting the API server is in the
+ * process of booting up so it's worth waiting and trying again.
+ */
+ sleep(1);
+ ++seconds_waited;
+
+ } else {
+ /* The server was reached but it returned an error */
+ EMSG("API server HTTP error: %ld", http_code);
+ return false;
+ }
+
+ } while (seconds_waited < RESTAPI_LOCATOR_MAX_API_WAIT);
+
+ IMSG("API server not reachable");
+
+ return false;
+}
+
+static void prepare_service_url(const char *sn, char *url_buf, size_t url_buf_size)
+{
+ strncpy(url_buf, RESTAPI_LOCATOR_API_URL, url_buf_size);
+
+ size_t url_len = strnlen(url_buf, url_buf_size);
+
+ assert(url_len < url_buf_size);
+
+ size_t remaining_space = url_buf_size - url_len;
+
+ url_len += sn_read_service(sn, &url_buf[url_len], remaining_space);
+
+ assert(url_len < url_buf_size - 1);
+
+ url_buf[url_len] = '/';
+ url_buf[url_len + 1] = '\0';
+}
+
+static struct service_context *query(const char *sn, int *status)
+{
+ *status = -1;
+
+ if (!probe_api_server())
+ return NULL;
+
+ /* API server reachable so check if service endpoint exists */
+ char service_url[HTTP_CALLER_MAX_URL_LEN];
+ long http_code = 0;
+
+ prepare_service_url(sn, service_url, sizeof(service_url));
+
+ if (!http_caller_probe(service_url, &http_code)) {
+ if (http_code != 404)
+ EMSG("Unexpected HTTP error: %ld", http_code);
+
+ /* Service endpoint not reachable */
+ return NULL;
+ }
+
+ return restapi_service_context_create(service_url);
+}
+
+const struct service_location_strategy *restapi_location_strategy(void)
+{
+ static const struct service_location_strategy strategy = { query };
+
+ return &strategy;
+}
diff --git a/components/service/locator/remote/restapi/restapi_location_strategy.h b/components/service/locator/remote/restapi/restapi_location_strategy.h
new file mode 100644
index 000000000..3a352ae01
--- /dev/null
+++ b/components/service/locator/remote/restapi/restapi_location_strategy.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RESTAPI_LOCATION_STRATEGY_H
+#define RESTAPI_LOCATION_STRATEGY_H
+
+#include "service_locator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Returns a service_location_strategy for locating a service reached via a
+ * REST API that presents a call endpoint for RPC access to the service. The
+ * FW Test API provides such call endpoints.
+ */
+const struct service_location_strategy *restapi_location_strategy(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RESTAPI_LOCATION_STRATEGY_H */
diff --git a/components/service/locator/remote/restapi/restapi_service_context.c b/components/service/locator/remote/restapi/restapi_service_context.c
new file mode 100644
index 000000000..92d3f2ad8
--- /dev/null
+++ b/components/service/locator/remote/restapi/restapi_service_context.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "restapi_service_context.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "rpc/http/caller/http_caller.h"
+#include "trace.h"
+
+/**
+ * A service_context that represents a service instance reached via
+ * a remote REST API
+ */
+struct restapi_service_context {
+ struct service_context service_context;
+ char rpc_call_url[HTTP_CALLER_MAX_URL_LEN];
+};
+
+/* Concrete service_context methods */
+static rpc_session_handle restapi_service_context_open(void *context, struct rpc_caller **caller);
+static void restapi_service_context_close(void *context, rpc_session_handle session_handle);
+static void restapi_service_context_relinquish(void *context);
+
+struct service_context *restapi_service_context_create(const char *service_url)
+{
+ struct restapi_service_context *new_context =
+ (struct restapi_service_context *)calloc(1, sizeof(struct restapi_service_context));
+
+ if (!new_context) {
+ EMSG("Failed to alloc restapi_service_context");
+ return NULL;
+ }
+
+ strncpy(new_context->rpc_call_url, service_url, HTTP_CALLER_MAX_URL_LEN - 1);
+ strncat(new_context->rpc_call_url, "call/", HTTP_CALLER_MAX_URL_LEN - 1);
+
+ new_context->service_context.context = new_context;
+ new_context->service_context.open = restapi_service_context_open;
+ new_context->service_context.close = restapi_service_context_close;
+ new_context->service_context.relinquish = restapi_service_context_relinquish;
+
+ return &new_context->service_context;
+}
+
+static rpc_session_handle restapi_service_context_open(void *context, struct rpc_caller **caller)
+{
+ struct restapi_service_context *this_context = (struct restapi_service_context *)context;
+ rpc_session_handle session_handle = NULL;
+
+ struct http_caller *http_caller =
+ (struct http_caller *)calloc(1, sizeof(struct http_caller));
+
+ if (http_caller) {
+ *caller = http_caller_init(http_caller);
+
+ int status = http_caller_open(http_caller, this_context->rpc_call_url);
+
+ if (status == 0) {
+ /* Successfully opened session */
+ session_handle = http_caller;
+ } else {
+ /* Failed to open session */
+ http_caller_close(http_caller);
+ http_caller_deinit(http_caller);
+ free(http_caller);
+ }
+ }
+
+ return session_handle;
+}
+
+static void restapi_service_context_close(void *context, rpc_session_handle session_handle)
+{
+ struct http_caller *http_caller = (struct http_caller *)session_handle;
+
+ (void)context;
+
+ if (http_caller) {
+ http_caller_close(http_caller);
+ http_caller_deinit(http_caller);
+ free(http_caller);
+ }
+}
+
+static void restapi_service_context_relinquish(void *context)
+{
+ struct restapi_service_context *this_context = (struct restapi_service_context *)context;
+
+ free(this_context);
+}
diff --git a/components/service/locator/remote/restapi/restapi_service_context.h b/components/service/locator/remote/restapi/restapi_service_context.h
new file mode 100644
index 000000000..8f6cd2974
--- /dev/null
+++ b/components/service/locator/remote/restapi/restapi_service_context.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RESTAPI_SERVICE_CONTEXT_H
+#define RESTAPI_SERVICE_CONTEXT_H
+
+#include "service_locator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Construct a service context
+ *
+ * Factory method to create a service context to represent a service instance
+ * reachable using the provided URL.
+ *
+ * \param[in] service_url URL string for the service API endpoint
+ *
+ * \return Pointer to constructed service_context
+ */
+struct service_context *restapi_service_context_create(const char *service_url);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RESTAPI_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/service_locator.c b/components/service/locator/service_locator.c
index 6f1f21803..d1efc9bb5 100644
--- a/components/service/locator/service_locator.c
+++ b/components/service/locator/service_locator.c
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <service_locator.h>
+#include "service_locator.h"
#include "service_name.h"
#include <assert.h>
#include <stddef.h>
@@ -16,59 +16,56 @@
*/
static struct service_locator
{
- unsigned int num_strategies;
- const struct service_location_strategy *strategies[SERVICE_LOCATOR_MAX_STATEGIES];
+ unsigned int num_strategies;
+ const struct service_location_strategy *strategies[SERVICE_LOCATOR_MAX_STATEGIES];
} service_locator_instance = { .num_strategies = 0 };
void service_locator_init(void)
{
- if (service_locator_instance.num_strategies == 0) service_locator_envinit();
+ if (service_locator_instance.num_strategies == 0) service_locator_envinit();
}
void service_locator_register_strategy(const struct service_location_strategy *strategy)
{
- assert(service_locator_instance.num_strategies < SERVICE_LOCATOR_MAX_STATEGIES);
+ assert(service_locator_instance.num_strategies < SERVICE_LOCATOR_MAX_STATEGIES);
- if (service_locator_instance.num_strategies < SERVICE_LOCATOR_MAX_STATEGIES) {
+ if (service_locator_instance.num_strategies < SERVICE_LOCATOR_MAX_STATEGIES) {
- service_locator_instance.strategies[service_locator_instance.num_strategies] = strategy;
- ++service_locator_instance.num_strategies;
- }
+ service_locator_instance.strategies[service_locator_instance.num_strategies] = strategy;
+ ++service_locator_instance.num_strategies;
+ }
}
-struct service_context *service_locator_query(const char *sn, int *status)
+struct service_context *service_locator_query(const char *sn)
{
- struct service_context *located_context = NULL;
- unsigned int index = 0;
+ struct service_context *located_context = NULL;
+ unsigned int index = 0;
- if (sn_is_valid(sn)) {
+ if (sn_is_valid(sn)) {
- while (!located_context && (index < service_locator_instance.num_strategies)) {
+ while (!located_context && (index < service_locator_instance.num_strategies)) {
- located_context = service_locator_instance.strategies[index]->query(sn, status);
- ++index;
- }
- }
+ located_context = service_locator_instance.strategies[index]->query(sn);
+ ++index;
+ }
+ }
- return located_context;
+ return located_context;
}
-rpc_session_handle service_context_open(struct service_context *s, uint32_t encoding, struct rpc_caller **caller)
+struct rpc_caller_session *service_context_open(struct service_context *s)
{
- rpc_session_handle handle = s->open(s->context, caller);
- if (handle) rpc_caller_set_encoding_scheme(*caller, encoding);
-
- return handle;
+ return s->open(s->context);
}
-void service_context_close(struct service_context *s, rpc_session_handle session_handle)
+void service_context_close(struct service_context *s, struct rpc_caller_session *session)
{
- s->close(s->context, session_handle);
+ s->close(s->context, session);
}
void service_context_relinquish(struct service_context *s)
{
- s->relinquish(s->context);
+ s->relinquish(s->context);
}
diff --git a/components/service/locator/service_name.c b/components/service/locator/service_name.c
index 0999787f5..440db9b9d 100644
--- a/components/service/locator/service_name.c
+++ b/components/service/locator/service_name.c
@@ -180,7 +180,7 @@ unsigned int sn_get_service_instance(const char *sn)
size_t digit_index = fields.instance_pos + fields.instance_len - 1 - i;
char digit = sn[digit_index];
- if (isdigit(digit)) {
+ if (isdigit((int)digit)) {
instance += ((digit - '0') * multiplier);
multiplier *= 10;
diff --git a/components/service/locator/sp/ffa/spffa_location_strategy.c b/components/service/locator/sp/ffa/spffa_location_strategy.c
index 71319d949..df06bfc48 100644
--- a/components/service/locator/sp/ffa/spffa_location_strategy.c
+++ b/components/service/locator/sp/ffa/spffa_location_strategy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,15 +7,15 @@
#include <stdbool.h>
#include "spffa_location_strategy.h"
#include "spffa_service_context.h"
+#include "sp_discovery.h"
#include <common/uuid/uuid.h>
#include <service/locator/service_name.h>
-#include <rpc/ffarpc/caller/sp/ffarpc_caller.h>
+#include "components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.h"
#include <trace.h>
-static struct service_context *query(const char *sn, int *status);
-static bool discover_partition(const struct uuid_octets *uuid, uint16_t *partition_id);
+static struct service_context *query(const char *sn);
-const struct service_location_strategy *spffa_location_strategy(void)
+const struct service_location_strategy *sp_ts_location_strategy(void)
{
static const struct service_location_strategy strategy = { query };
return &strategy;
@@ -26,74 +26,35 @@ const struct service_location_strategy *spffa_location_strategy(void)
* endpoints reachable via FFA from within a client secure partition where
* associated service endpoints are explicitly defined by configuration data.
* The service to locate is specified by a service name that consists of a
- * UUID and an optional instance number. If pesent, the instance number
+ * UUID and an optional instance number. If present, the instance number
* is treated as the destination RPC interface id. If not specified,
* an interface id of zero is assumed.
*/
-static struct service_context *query(const char *sn, int *status)
+static struct service_context *query(const char *sn)
{
- struct service_context *result = NULL;
+ struct uuid_canonical uuid = { 0 };
+ struct rpc_uuid service_uuid = { 0 };
+ struct sp_ts_service_context *new_context = NULL;
/* This strategy only locates endpoints reachable via FFA */
- if (sn_check_authority(sn, "ffa")) {
-
- struct uuid_canonical uuid;
-
- if (sn_read_service(sn, uuid.characters, UUID_CANONICAL_FORM_LEN + 1) &&
- uuid_is_valid(uuid.characters)) {
-
- uint16_t partition_id;
- struct uuid_octets uuid_octets;
-
- uuid_parse_to_octets(uuid.characters, uuid_octets.octets, UUID_OCTETS_LEN);
-
- if (discover_partition(&uuid_octets, &partition_id)) {
-
- unsigned int iface_id =
- sn_get_service_instance(sn);
-
- struct spffa_service_context *new_context =
- spffa_service_context_create(partition_id, iface_id);
-
- if (new_context) {
-
- result = &new_context->service_context;
- }
- else {
-
- EMSG("locate query: context create failed");
- }
- }
- else {
-
- EMSG("locate query: partition not discovered");
- }
- }
- else {
-
- EMSG("locate query: invalid uuid");
- }
+ if (!sn_check_authority(sn, "ffa")) {
+ EMSG("failed to check authority");
+ return NULL;
}
- return result;
-}
-
-static bool discover_partition(const struct uuid_octets *uuid, uint16_t *partition_id)
-{
- bool discovered = false;
- struct ffarpc_caller ffarpc_caller;
- uint16_t discovered_partitions[1];
-
- ffarpc_caller_init(&ffarpc_caller);
+ if (!sn_read_service(sn, uuid.characters, sizeof(uuid.characters)) ||
+ !uuid_is_valid(uuid.characters)) {
+ EMSG("invalid uuid");
+ return NULL;
+ }
- if (ffarpc_caller_discover(uuid->octets,
- discovered_partitions, sizeof(discovered_partitions)/sizeof(uint16_t))) {
+ uuid_parse_to_octets(uuid.characters, service_uuid.uuid, sizeof(service_uuid.uuid));
- *partition_id = discovered_partitions[0];
- discovered = true;
+ new_context = spffa_service_context_create(&service_uuid);
+ if (!new_context) {
+ EMSG("context create failed");
+ return NULL;
}
- ffarpc_caller_deinit(&ffarpc_caller);
-
- return discovered;
+ return &new_context->service_context;
}
diff --git a/components/service/locator/sp/ffa/spffa_location_strategy.h b/components/service/locator/sp/ffa/spffa_location_strategy.h
index edaf76b30..55762c5dc 100644
--- a/components/service/locator/sp/ffa/spffa_location_strategy.h
+++ b/components/service/locator/sp/ffa/spffa_location_strategy.h
@@ -18,7 +18,7 @@ extern "C" {
* hosted in a secure partition, accessed using FFA from another secure
* partition.
*/
-const struct service_location_strategy *spffa_location_strategy(void);
+const struct service_location_strategy *sp_ts_location_strategy(void);
#ifdef __cplusplus
}
diff --git a/components/service/locator/sp/ffa/spffa_service_context.c b/components/service/locator/sp/ffa/spffa_service_context.c
index 21cf72fd6..0c1616fc6 100644
--- a/components/service/locator/sp/ffa/spffa_service_context.c
+++ b/components/service/locator/sp/ffa/spffa_service_context.c
@@ -1,82 +1,75 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "spffa_service_context.h"
-#include <rpc/ffarpc/caller/sp/ffarpc_caller.h>
+#include "rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.h"
+#include "sp_discovery.h"
#include <stdlib.h>
+#include <string.h>
/* Concrete service_context methods */
-static rpc_session_handle spffa_service_context_open(void *context, struct rpc_caller **caller);
-static void spffa_service_context_close(void *context, rpc_session_handle session_handle);
-static void spffa_service_context_relinquish(void *context);
+static struct rpc_caller_session *sp_ts_service_context_open(void *context);
+static void sp_ts_service_context_close(void *context, struct rpc_caller_session *session);
+static void sp_ts_service_context_relinquish(void *context);
-struct spffa_service_context *spffa_service_context_create(
- uint16_t partition_id, uint16_t iface_id)
+struct sp_ts_service_context *spffa_service_context_create(const struct rpc_uuid *service_uuid)
{
- struct spffa_service_context *new_context =
- (struct spffa_service_context*)malloc(sizeof(struct spffa_service_context));
+ struct sp_ts_service_context *new_context =
+ (struct sp_ts_service_context*)malloc(sizeof(struct sp_ts_service_context));
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
- if (new_context) {
- new_context->partition_id = partition_id;
- new_context->iface_id = iface_id;
+ if (!new_context)
+ return NULL;
- new_context->service_context.context = new_context;
- new_context->service_context.open = spffa_service_context_open;
- new_context->service_context.close = spffa_service_context_close;
- new_context->service_context.relinquish = spffa_service_context_relinquish;
+ rpc_status = ts_rpc_caller_sp_init(&new_context->caller);
+ if (rpc_status != RPC_SUCCESS) {
+ free(new_context);
+ return NULL;
}
+ memcpy(&new_context->service_uuid, service_uuid, sizeof(new_context->service_uuid));
+
+ new_context->service_context.context = new_context;
+ new_context->service_context.open = sp_ts_service_context_open;
+ new_context->service_context.close = sp_ts_service_context_close;
+ new_context->service_context.relinquish = sp_ts_service_context_relinquish;
+
return new_context;
}
-static rpc_session_handle spffa_service_context_open(void *context, struct rpc_caller **caller)
+static struct rpc_caller_session *sp_ts_service_context_open(void *context)
{
- struct spffa_service_context *this_context = (struct spffa_service_context*)context;
- rpc_session_handle session_handle = NULL;
- struct ffarpc_caller *ffarpc_caller =
- (struct ffarpc_caller*)malloc(sizeof(struct ffarpc_caller));
-
- if (ffarpc_caller) {
-
- *caller = ffarpc_caller_init(ffarpc_caller);
- int status = ffarpc_caller_open(ffarpc_caller,
- this_context->partition_id, this_context->iface_id);
-
- if (status == 0) {
- /* Successfully opened session */
- session_handle = ffarpc_caller;
- }
- else {
- /* Failed to open session */
- ffarpc_caller_close(ffarpc_caller);
- ffarpc_caller_deinit(ffarpc_caller);
- free(ffarpc_caller);
- }
+ struct sp_ts_service_context *this_context = (struct sp_ts_service_context *)context;
+ struct rpc_caller_session *session =
+ (struct rpc_caller_session *)calloc(1, sizeof(struct rpc_caller_session));
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ if (!session)
+ return NULL;
+
+ rpc_status = rpc_caller_session_find_and_open(session, &this_context->caller,
+ &this_context->service_uuid, 4096);
+ if (rpc_status != RPC_SUCCESS) {
+ free(session);
+ return NULL;
}
- return session_handle;
+ return session;
}
-static void spffa_service_context_close(void *context, rpc_session_handle session_handle)
+static void sp_ts_service_context_close(void *context, struct rpc_caller_session *session)
{
- struct ffarpc_caller *ffarpc_caller = (struct ffarpc_caller*)session_handle;
-
(void)context;
- if (ffarpc_caller) {
-
- ffarpc_caller_close(ffarpc_caller);
- ffarpc_caller_deinit(ffarpc_caller);
- free(ffarpc_caller);
- }
+ rpc_caller_session_close(session);
+ free(session);
}
-static void spffa_service_context_relinquish(void *context)
+static void sp_ts_service_context_relinquish(void *context)
{
- struct spffa_service_context *this_context = (struct spffa_service_context*)context;
- free(this_context);
+ free(context);
}
diff --git a/components/service/locator/sp/ffa/spffa_service_context.h b/components/service/locator/sp/ffa/spffa_service_context.h
index 26e6fb9d6..ff9b2f207 100644
--- a/components/service/locator/sp/ffa/spffa_service_context.h
+++ b/components/service/locator/sp/ffa/spffa_service_context.h
@@ -18,20 +18,18 @@ extern "C" {
* a partition, accessed via FFA. This service_context is suitable
* for use by client applications running in a secure partition.
*/
-struct spffa_service_context
+struct sp_ts_service_context
{
struct service_context service_context;
- uint16_t partition_id;
- uint16_t iface_id;
+ struct rpc_caller_interface caller;
+ struct rpc_uuid service_uuid;
};
/*
* Factory method to create a service context associated with the specified
* partition id and RPC interface instance.
*/
-struct spffa_service_context *spffa_service_context_create(
- uint16_t partition_id,
- uint16_t iface_id);
+struct sp_ts_service_context *spffa_service_context_create(const struct rpc_uuid *service_uuid);
#ifdef __cplusplus
}
diff --git a/components/service/locator/sp/sp_env.c b/components/service/locator/sp/sp_env.c
index 51507cb35..585ab21f0 100644
--- a/components/service/locator/sp/sp_env.c
+++ b/components/service/locator/sp/sp_env.c
@@ -14,5 +14,5 @@ void service_locator_envinit(void)
* Register all service location strategies that could be used
* to locate services from a secure partition.
*/
- service_locator_register_strategy(spffa_location_strategy());
+ service_locator_register_strategy(sp_ts_location_strategy());
}
diff --git a/components/service/locator/standalone/services/attestation/attestation_service_context.cpp b/components/service/locator/standalone/services/attestation/attestation_service_context.cpp
index df676cd4d..24778e6a8 100644
--- a/components/service/locator/standalone/services/attestation/attestation_service_context.cpp
+++ b/components/service/locator/standalone/services/attestation/attestation_service_context.cpp
@@ -88,10 +88,9 @@ void attestation_service_context::do_init()
/* Initialize the attestation service provider */
local_attest_key_mngr_init(LOCAL_ATTEST_KEY_MNGR_VOLATILE_IAK);
- struct rpc_interface *attest_ep = attest_provider_init(&m_attest_provider);
+ struct rpc_service_interface *attest_ep = attest_provider_init(&m_attest_provider);
- attest_provider_register_serializer(&m_attest_provider,
- TS_RPC_ENCODING_PACKED_C, packedc_attest_provider_serializer_instance());
+ attest_provider_register_serializer(&m_attest_provider, packedc_attest_provider_serializer_instance());
standalone_service_context::set_rpc_interface(attest_ep);
}
diff --git a/components/service/locator/standalone/services/block-storage/block_storage_service_context.cpp b/components/service/locator/standalone/services/block-storage/block_storage_service_context.cpp
new file mode 100644
index 000000000..56f91db7f
--- /dev/null
+++ b/components/service/locator/standalone/services/block-storage/block_storage_service_context.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cstring>
+#include "service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h"
+#include "service/block_storage/factory/rpmb/block_store_factory.h"
+#include "block_storage_service_context.h"
+
+block_storage_service_context::block_storage_service_context(const char *sn) :
+ standalone_service_context(sn),
+ m_block_storage_provider(),
+ m_block_store(NULL)
+{
+
+}
+
+block_storage_service_context::~block_storage_service_context()
+{
+
+}
+
+void block_storage_service_context::do_init()
+{
+ /* Create backend block store */
+ m_block_store = rpmb_block_store_factory_create();
+ assert(m_block_store);
+
+ /* Initialise the block storage service provider */
+ struct rpc_service_interface *rpc_iface = block_storage_provider_init(
+ &m_block_storage_provider,
+ m_block_store);
+ assert(rpc_iface);
+
+ block_storage_provider_register_serializer(&m_block_storage_provider,
+ packedc_block_storage_serializer_instance());
+
+ standalone_service_context::set_rpc_interface(rpc_iface);
+}
+
+void block_storage_service_context::do_deinit()
+{
+ block_storage_provider_deinit(&m_block_storage_provider);
+ rpmb_block_store_factory_destroy(m_block_store);
+}
diff --git a/components/service/locator/standalone/services/block-storage/block_storage_service_context.h b/components/service/locator/standalone/services/block-storage/block_storage_service_context.h
new file mode 100644
index 000000000..c47aedee3
--- /dev/null
+++ b/components/service/locator/standalone/services/block-storage/block_storage_service_context.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_BLOCK_STORAGE_SERVICE_CONTEXT_H
+#define STANDALONE_BLOCK_STORAGE_SERVICE_CONTEXT_H
+
+#include <service/locator/standalone/standalone_service_context.h>
+#include <rpc/direct/direct_caller.h>
+#include <service/block_storage/provider/block_storage_provider.h>
+#include <service/block_storage/block_store/block_store.h>
+
+class block_storage_service_context : public standalone_service_context
+{
+public:
+ block_storage_service_context(const char *sn);
+ virtual ~block_storage_service_context();
+
+private:
+
+ void do_init();
+ void do_deinit();
+
+ struct block_storage_provider m_block_storage_provider;
+ struct block_store *m_block_store;
+};
+
+#endif /* STANDALONE_BLOCK_STORAGE_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/services/block-storage/component.cmake b/components/service/locator/standalone/services/block-storage/component.cmake
new file mode 100644
index 000000000..68f258b0f
--- /dev/null
+++ b/components/service/locator/standalone/services/block-storage/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/block_storage_service_context.cpp"
+ )
diff --git a/components/service/locator/standalone/services/crypto/crypto_service_context.cpp b/components/service/locator/standalone/services/crypto/crypto_service_context.cpp
index c22bb0baf..7840803ea 100644
--- a/components/service/locator/standalone/services/crypto/crypto_service_context.cpp
+++ b/components/service/locator/standalone/services/crypto/crypto_service_context.cpp
@@ -8,13 +8,14 @@
#include <service/crypto/factory/crypto_provider_factory.h>
#include <service/crypto/backend/mbedcrypto/mbedcrypto_backend.h>
-crypto_service_context::crypto_service_context(const char *sn) :
+crypto_service_context::crypto_service_context(const char *sn, unsigned int encoding) :
standalone_service_context(sn),
+ m_encoding(encoding),
m_crypto_provider(NULL),
m_storage_client(),
m_null_store(),
m_storage_service_context(NULL),
- m_storage_session_handle(NULL)
+ m_storage_session(NULL)
{
}
@@ -28,24 +29,21 @@ void crypto_service_context::do_init()
{
struct storage_backend *storage_backend = NULL;
struct storage_backend *null_storage_backend = null_store_init(&m_null_store);
- struct rpc_caller *storage_caller = NULL;
- int status;
/* Locate and open RPC session with internal-trusted-storage service to
* provide a persistent keystore
*/
m_storage_service_context =
- service_locator_query("sn:trustedfirmware.org:internal-trusted-storage:0", &status);
+ service_locator_query("sn:trustedfirmware.org:internal-trusted-storage:0");
if (m_storage_service_context) {
- m_storage_session_handle =
- service_context_open(m_storage_service_context,
- TS_RPC_ENCODING_PACKED_C, &storage_caller);
+ m_storage_session =
+ service_context_open(m_storage_service_context);
- if (m_storage_session_handle) {
+ if (m_storage_session) {
- storage_backend = secure_storage_client_init(&m_storage_client, storage_caller);
+ storage_backend = secure_storage_client_init(&m_storage_client, m_storage_session);
}
}
@@ -58,11 +56,15 @@ void crypto_service_context::do_init()
}
/* Initialise the crypto service provider */
- struct rpc_interface *crypto_iface = NULL;
+ struct rpc_service_interface *crypto_iface = NULL;
if (mbedcrypto_backend_init(storage_backend, 0) == PSA_SUCCESS) {
- m_crypto_provider = crypto_provider_factory_create();
+ if (m_encoding == TS_RPC_ENCODING_PACKED_C)
+ m_crypto_provider = crypto_provider_factory_create();
+ else
+ m_crypto_provider = crypto_protobuf_provider_factory_create();
+
crypto_iface = service_provider_get_rpc_interface(&m_crypto_provider->base_provider);
}
@@ -71,9 +73,9 @@ void crypto_service_context::do_init()
void crypto_service_context::do_deinit()
{
- if (m_storage_session_handle) {
- service_context_close(m_storage_service_context, m_storage_session_handle);
- m_storage_session_handle = NULL;
+ if (m_storage_session) {
+ service_context_close(m_storage_service_context, m_storage_session);
+ m_storage_session = NULL;
}
if (m_storage_service_context) {
diff --git a/components/service/locator/standalone/services/crypto/crypto_service_context.h b/components/service/locator/standalone/services/crypto/crypto_service_context.h
index 6010a4e2b..b3be294d8 100644
--- a/components/service/locator/standalone/services/crypto/crypto_service_context.h
+++ b/components/service/locator/standalone/services/crypto/crypto_service_context.h
@@ -16,7 +16,7 @@
class crypto_service_context : public standalone_service_context
{
public:
- crypto_service_context(const char *sn);
+ crypto_service_context(const char *sn, unsigned int encoding);
virtual ~crypto_service_context();
private:
@@ -24,11 +24,12 @@ private:
void do_init();
void do_deinit();
+ unsigned int m_encoding;
struct crypto_provider *m_crypto_provider;
struct secure_storage_client m_storage_client;
struct null_store m_null_store;
struct service_context *m_storage_service_context;
- rpc_session_handle m_storage_session_handle;
+ struct rpc_caller_session *m_storage_session;
};
#endif /* STANDALONE_CRYPTO_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/services/fwu/component.cmake b/components/service/locator/standalone/services/fwu/component.cmake
new file mode 100644
index 000000000..6242dce2d
--- /dev/null
+++ b/components/service/locator/standalone/services/fwu/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_service_context.cpp"
+ )
diff --git a/components/service/locator/standalone/services/fwu/fwu_service_context.cpp b/components/service/locator/standalone/services/fwu/fwu_service_context.cpp
new file mode 100644
index 000000000..2980d2aaa
--- /dev/null
+++ b/components/service/locator/standalone/services/fwu/fwu_service_context.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fwu_service_context.h"
+
+struct rpc_service_interface *fwu_service_context::m_provider_iface = NULL;
+
+fwu_service_context::fwu_service_context(const char *sn)
+ : standalone_service_context(sn)
+{
+}
+
+fwu_service_context::~fwu_service_context()
+{
+}
+
+void fwu_service_context::set_provider(struct rpc_service_interface *iface)
+{
+ m_provider_iface = iface;
+}
+
+void fwu_service_context::do_init()
+{
+ standalone_service_context::set_rpc_interface(m_provider_iface);
+}
+
+void fwu_service_context::do_deinit()
+{
+ set_provider(NULL);
+}
+
+void fwu_service_context_set_provider(struct rpc_service_interface *iface)
+{
+ fwu_service_context::set_provider(iface);
+} \ No newline at end of file
diff --git a/components/service/locator/standalone/services/fwu/fwu_service_context.h b/components/service/locator/standalone/services/fwu/fwu_service_context.h
new file mode 100644
index 000000000..9a7b9cbb8
--- /dev/null
+++ b/components/service/locator/standalone/services/fwu/fwu_service_context.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_FWU_SERVICE_CONTEXT_H
+#define STANDALONE_FWU_SERVICE_CONTEXT_H
+
+#include "service/locator/standalone/standalone_service_context.h"
+
+class fwu_service_context : public standalone_service_context {
+public:
+ explicit fwu_service_context(const char *sn);
+ virtual ~fwu_service_context();
+
+ static void set_provider(struct rpc_service_interface *iface);
+
+private:
+ void do_init();
+ void do_deinit();
+
+ static struct rpc_service_interface *m_provider_iface;
+};
+
+/*
+ * Export function to set the service provider
+ */
+#ifdef EXPORT_PUBLIC_INTERFACE_FWU_SERVICE_CONTEXT
+#define FWU_SERVICE_CONTEXT_EXPORTED __attribute__((__visibility__("default")))
+#else
+#define FWU_SERVICE_CONTEXT_EXPORTED
+#endif
+
+FWU_SERVICE_CONTEXT_EXPORTED void fwu_service_context_set_provider(struct rpc_service_interface *iface);
+
+#endif /* STANDALONE_FWU_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/services/internal-trusted-storage/its_service_context.cpp b/components/service/locator/standalone/services/internal-trusted-storage/its_service_context.cpp
index 72cc62ee1..e2a58dccf 100644
--- a/components/service/locator/standalone/services/internal-trusted-storage/its_service_context.cpp
+++ b/components/service/locator/standalone/services/internal-trusted-storage/its_service_context.cpp
@@ -5,6 +5,7 @@
*/
#include "its_service_context.h"
+#include "components/service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
its_service_context::its_service_context(const char *sn) :
standalone_service_context(sn),
@@ -21,8 +22,10 @@ its_service_context::~its_service_context()
void its_service_context::do_init()
{
+ const rpc_uuid service_uuid = {.uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID};
struct storage_backend *storage_backend = mock_store_init(&m_mock_store);
- struct rpc_interface *storage_ep = secure_storage_provider_init(&m_storage_provider, storage_backend);
+ struct rpc_service_interface *storage_ep =
+ secure_storage_provider_init(&m_storage_provider, storage_backend, &service_uuid);
standalone_service_context::set_rpc_interface(storage_ep);
}
diff --git a/components/service/locator/standalone/services/protected-storage/ps_service_context.cpp b/components/service/locator/standalone/services/protected-storage/ps_service_context.cpp
index cda49f64b..edad9df63 100644
--- a/components/service/locator/standalone/services/protected-storage/ps_service_context.cpp
+++ b/components/service/locator/standalone/services/protected-storage/ps_service_context.cpp
@@ -1,15 +1,21 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "ps_service_context.h"
+#include "service/block_storage/factory/client/block_store_factory.h"
+#include "service/secure_storage/backend/secure_flash_store/secure_flash_store.h"
+#include "service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
+#include "media/disk/guid.h"
+#include <assert.h>
ps_service_context::ps_service_context(const char *sn) :
- standalone_service_context(sn),
- m_storage_provider(),
- m_mock_store()
+ standalone_service_context(sn),
+ m_storage_provider(),
+ m_sfs_flash_adapter(),
+ m_block_store(NULL)
{
}
@@ -21,14 +27,37 @@ ps_service_context::~ps_service_context()
void ps_service_context::do_init()
{
- struct storage_backend *storage_backend = mock_store_init(&m_mock_store);
- struct rpc_interface *storage_ep = secure_storage_provider_init(&m_storage_provider, storage_backend);
+ struct uuid_octets guid;
+ const struct sfs_flash_info_t *flash_info = NULL;
+ const struct rpc_uuid service_uuid = {.uuid = TS_PSA_PROTECTED_STORAGE_UUID };
- standalone_service_context::set_rpc_interface(storage_ep);
+ uuid_guid_octets_from_canonical(&guid,
+ DISK_GUID_UNIQUE_PARTITION_PSA_PS);
+
+ m_block_store = client_block_store_factory_create("sn:trustedfirmware.org:block-storage:0");
+ assert(m_block_store != NULL);
+
+ psa_status_t status = sfs_flash_block_store_adapter_init(
+ &m_sfs_flash_adapter,
+ 0,
+ m_block_store,
+ &guid,
+ MIN_FLASH_BLOCK_SIZE,
+ MAX_NUM_FILES,
+ &flash_info);
+
+ assert(status == PSA_SUCCESS);
+
+ struct storage_backend *storage_backend = sfs_init(flash_info);
+ struct rpc_service_interface *storage_ep = secure_storage_provider_init(
+ &m_storage_provider, storage_backend, &service_uuid);
+
+ standalone_service_context::set_rpc_interface(storage_ep);
}
void ps_service_context::do_deinit()
{
- secure_storage_provider_deinit(&m_storage_provider);
- mock_store_deinit(&m_mock_store);
+ secure_storage_provider_deinit(&m_storage_provider);
+ client_block_store_factory_destroy(m_block_store);
+ m_block_store = NULL;
}
diff --git a/components/service/locator/standalone/services/protected-storage/ps_service_context.h b/components/service/locator/standalone/services/protected-storage/ps_service_context.h
index 2e3c46edb..81d5c464d 100644
--- a/components/service/locator/standalone/services/protected-storage/ps_service_context.h
+++ b/components/service/locator/standalone/services/protected-storage/ps_service_context.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,21 +9,26 @@
#include <service/locator/standalone/standalone_service_context.h>
#include <service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h>
-#include <service/secure_storage/backend/mock_store/mock_store.h>
+#include <service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.h>
+#include <service/block_storage/block_store/block_store.h>
class ps_service_context : public standalone_service_context
{
public:
- ps_service_context(const char *sn);
- virtual ~ps_service_context();
+ ps_service_context(const char *sn);
+ virtual ~ps_service_context();
private:
- void do_init();
- void do_deinit();
+ void do_init();
+ void do_deinit();
- struct secure_storage_provider m_storage_provider;
- struct mock_store m_mock_store;
+ static const size_t MAX_NUM_FILES = 10;
+ static const size_t MIN_FLASH_BLOCK_SIZE = 4096;
+
+ struct secure_storage_provider m_storage_provider;
+ struct sfs_flash_block_store_adapter m_sfs_flash_adapter;
+ struct block_store *m_block_store;
};
#endif /* STANDALONE_PS_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/services/rpmb/component.cmake b/components/service/locator/standalone/services/rpmb/component.cmake
new file mode 100644
index 000000000..6bd8b1f43
--- /dev/null
+++ b/components/service/locator/standalone/services/rpmb/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_service_context.cpp"
+ )
diff --git a/components/service/locator/standalone/services/rpmb/rpmb_service_context.cpp b/components/service/locator/standalone/services/rpmb/rpmb_service_context.cpp
new file mode 100644
index 000000000..710a998cb
--- /dev/null
+++ b/components/service/locator/standalone/services/rpmb/rpmb_service_context.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpmb_service_context.h"
+#include "service/rpmb/provider/rpmb_uuid.h"
+#include <assert.h>
+
+rpmb_service_context::rpmb_service_context(const char *sn) :
+ standalone_service_context(sn),
+ m_rpmb_provider(),
+ m_rpmb_backend(),
+ m_rpmb_backend_emulated()
+{
+
+}
+
+rpmb_service_context::~rpmb_service_context()
+{
+
+}
+
+void rpmb_service_context::do_init()
+{
+ const struct rpc_uuid service_uuid = {.uuid = TS_RPMB_SERVICE_UUID };
+
+ m_rpmb_backend = rpmb_backend_emulated_init(&m_rpmb_backend_emulated, RPMB_MULT);
+ assert(m_rpmb_backend != NULL);
+
+ struct rpc_service_interface *rpmb_service =
+ rpmb_provider_init(&m_rpmb_provider, m_rpmb_backend, &service_uuid);
+ assert(rpmb_service != NULL);
+
+ standalone_service_context::set_rpc_interface(rpmb_service);
+}
+
+void rpmb_service_context::do_deinit()
+{
+ rpmb_provider_deinit(&m_rpmb_provider);
+ m_rpmb_backend = NULL;
+ rpmb_backend_emulated_deinit(&m_rpmb_backend_emulated);
+}
diff --git a/components/service/locator/standalone/services/rpmb/rpmb_service_context.h b/components/service/locator/standalone/services/rpmb/rpmb_service_context.h
new file mode 100644
index 000000000..a6ad12be3
--- /dev/null
+++ b/components/service/locator/standalone/services/rpmb/rpmb_service_context.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_RPMB_SERVICE_CONTEXT_H
+#define STANDALONE_RPMB_SERVICE_CONTEXT_H
+
+#include "service/locator/standalone/standalone_service_context.h"
+#include "service/rpmb/backend/emulated/rpmb_backend_emulated.h"
+#include "service/rpmb/provider/rpmb_provider.h"
+
+class rpmb_service_context : public standalone_service_context
+{
+public:
+ rpmb_service_context(const char *sn);
+ virtual ~rpmb_service_context();
+
+private:
+
+ void do_init();
+ void do_deinit();
+
+ /* Set emulated RPMB size to 2 * 128kB */
+ static const uint16_t RPMB_MULT = 2;
+
+ struct rpmb_provider m_rpmb_provider;
+ struct rpmb_backend *m_rpmb_backend;
+ struct rpmb_backend_emulated m_rpmb_backend_emulated;
+};
+
+#endif /* STANDALONE_RPMB_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/services/smm-variable/smm_variable_service_context.cpp b/components/service/locator/standalone/services/smm-variable/smm_variable_service_context.cpp
index 0b289171a..ae4698f99 100644
--- a/components/service/locator/standalone/services/smm-variable/smm_variable_service_context.cpp
+++ b/components/service/locator/standalone/services/smm-variable/smm_variable_service_context.cpp
@@ -13,7 +13,7 @@ smm_variable_service_context::smm_variable_service_context(const char *sn) :
m_persistent_store_client(),
m_volatile_store(),
m_storage_service_context(NULL),
- m_storage_session_handle(NULL)
+ m_storage_session(NULL)
{
}
@@ -25,33 +25,29 @@ smm_variable_service_context::~smm_variable_service_context()
void smm_variable_service_context::do_init()
{
- /* Initialize the persistent storage backend - uses protected storage service */
+ /* Initialize the persistent storage backend - uses protected storage service */
struct storage_backend *peristent_backend = NULL;
- struct rpc_caller *storage_caller = NULL;
- int status = 0;
- /* Locate and open RPC session with the protected-storage service */
- m_storage_service_context =
- service_locator_query("sn:trustedfirmware.org:protected-storage:0", &status);
+ /* Locate and open RPC session with the protected-storage service */
+ m_storage_service_context =
+ service_locator_query("sn:trustedfirmware.org:protected-storage:0");
- if (m_storage_service_context) {
+ if (m_storage_service_context) {
- m_storage_session_handle = service_context_open(
- m_storage_service_context, TS_RPC_ENCODING_PACKED_C,
- &storage_caller);
+ m_storage_session = service_context_open(m_storage_service_context);
- if (m_storage_session_handle) {
+ if (m_storage_session) {
- peristent_backend = secure_storage_client_init(
- &m_persistent_store_client, storage_caller);
- }
- }
+ peristent_backend = secure_storage_client_init(
+ &m_persistent_store_client, m_storage_session);
+ }
+ }
/* Initialize the volatile storage backend */
struct storage_backend *volatile_backend = mock_store_init(&m_volatile_store);
/* Initialize the smm_variable service provider */
- struct rpc_interface *service_iface = smm_variable_provider_init(
+ struct rpc_service_interface *service_iface = smm_variable_provider_init(
&m_smm_variable_provider,
0, /* owner id */
MAX_VARIABLES,
@@ -63,17 +59,17 @@ void smm_variable_service_context::do_init()
void smm_variable_service_context::do_deinit()
{
- if (m_storage_session_handle) {
- service_context_close(m_storage_service_context, m_storage_session_handle);
- m_storage_session_handle = NULL;
- }
+ if (m_storage_session) {
+ service_context_close(m_storage_service_context, m_storage_session);
+ m_storage_session = NULL;
+ }
- if (m_storage_service_context) {
- service_context_relinquish(m_storage_service_context);
- m_storage_service_context = NULL;
- }
+ if (m_storage_service_context) {
+ service_context_relinquish(m_storage_service_context);
+ m_storage_service_context = NULL;
+ }
smm_variable_provider_deinit(&m_smm_variable_provider);
- secure_storage_client_deinit(&m_persistent_store_client);
- mock_store_deinit(&m_volatile_store);
+ secure_storage_client_deinit(&m_persistent_store_client);
+ mock_store_deinit(&m_volatile_store);
}
diff --git a/components/service/locator/standalone/services/smm-variable/smm_variable_service_context.h b/components/service/locator/standalone/services/smm-variable/smm_variable_service_context.h
index 011c97a9f..4420614cf 100644
--- a/components/service/locator/standalone/services/smm-variable/smm_variable_service_context.h
+++ b/components/service/locator/standalone/services/smm-variable/smm_variable_service_context.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,7 +10,7 @@
#include <stddef.h>
#include <stdint.h>
#include <service/locator/standalone/standalone_service_context.h>
-#include <service/smm_variable/provider/smm_variable_provider.h>
+#include <service/uefi/smm_variable/provider/smm_variable_provider.h>
#include <service/secure_storage/backend/secure_storage_client/secure_storage_client.h>
#include <service/secure_storage/backend/mock_store/mock_store.h>
@@ -34,7 +34,7 @@ private:
struct secure_storage_client m_persistent_store_client;
struct mock_store m_volatile_store;
struct service_context *m_storage_service_context;
- rpc_session_handle m_storage_session_handle;
+ struct rpc_caller_session *m_storage_session;
};
#endif /* STANDALONE_SMM_VARIABLE_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/services/test-runner/test_runner_service_context.cpp b/components/service/locator/standalone/services/test-runner/test_runner_service_context.cpp
index 103f18806..89aa40233 100644
--- a/components/service/locator/standalone/services/test-runner/test_runner_service_context.cpp
+++ b/components/service/locator/standalone/services/test-runner/test_runner_service_context.cpp
@@ -21,7 +21,7 @@ test_runner_service_context::~test_runner_service_context()
void test_runner_service_context::do_init()
{
- struct rpc_interface *test_runner_ep = test_runner_provider_init(&m_test_runner_provider);
+ struct rpc_service_interface *test_runner_ep = test_runner_provider_init(&m_test_runner_provider);
test_runner_provider_register_serializer(&m_test_runner_provider,
TS_RPC_ENCODING_PACKED_C, packedc_test_runner_provider_serializer_instance());
diff --git a/components/service/locator/standalone/standalone_env.cpp b/components/service/locator/standalone/standalone_env.cpp
index 7f7ce1378..438fc7ef5 100644
--- a/components/service/locator/standalone/standalone_env.cpp
+++ b/components/service/locator/standalone/standalone_env.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,15 +10,22 @@
#include <service/locator/standalone/services/protected-storage/ps_service_context.h>
#include <service/locator/standalone/services/test-runner/test_runner_service_context.h>
#include <service/locator/standalone/services/attestation/attestation_service_context.h>
+#include <service/locator/standalone/services/block-storage/block_storage_service_context.h>
+#include <service/locator/standalone/services/fwu/fwu_service_context.h>
#include <service/locator/standalone/services/smm-variable/smm_variable_service_context.h>
+#include <service/locator/standalone/services/rpmb/rpmb_service_context.h>
#include "standalone_location_strategy.h"
#include "standalone_service_registry.h"
void service_locator_envinit(void)
{
- static crypto_service_context crypto_context("sn:trustedfirmware.org:crypto:0");
+ static crypto_service_context crypto_context("sn:trustedfirmware.org:crypto:0", TS_RPC_ENCODING_PACKED_C);
standalone_service_registry::instance()->regsiter_service_instance(&crypto_context);
+ static crypto_service_context crypto_context_protobuf("sn:trustedfirmware.org:crypto-protobuf:0",
+ TS_RPC_ENCODING_PROTOBUF);
+ standalone_service_registry::instance()->regsiter_service_instance(&crypto_context_protobuf);
+
static its_service_context its_service_context("sn:trustedfirmware.org:internal-trusted-storage:0");
standalone_service_registry::instance()->regsiter_service_instance(&its_service_context);
@@ -31,8 +38,17 @@ void service_locator_envinit(void)
static attestation_service_context attestation_context("sn:trustedfirmware.org:attestation:0");
standalone_service_registry::instance()->regsiter_service_instance(&attestation_context);
+ static block_storage_service_context block_storage_context("sn:trustedfirmware.org:block-storage:0");
+ standalone_service_registry::instance()->regsiter_service_instance(&block_storage_context);
+
+ static fwu_service_context fwu_context("sn:trustedfirmware.org:fwu:0");
+ standalone_service_registry::instance()->regsiter_service_instance(&fwu_context);
+
static smm_variable_service_context smm_variable_context("sn:trustedfirmware.org:smm-variable:0");
standalone_service_registry::instance()->regsiter_service_instance(&smm_variable_context);
+ static rpmb_service_context rpmb_context("sn:trustedfirmware.org:rpmb:0");
+ standalone_service_registry::instance()->regsiter_service_instance(&rpmb_context);
+
service_locator_register_strategy(standalone_location_strategy());
}
diff --git a/components/service/locator/standalone/standalone_location_strategy.cpp b/components/service/locator/standalone/standalone_location_strategy.cpp
index 57e370c98..e48045313 100644
--- a/components/service/locator/standalone/standalone_location_strategy.cpp
+++ b/components/service/locator/standalone/standalone_location_strategy.cpp
@@ -8,18 +8,15 @@
#include "standalone_service_registry.h"
#include "standalone_service_context.h"
-static struct service_context *query(const char *sn, int *status)
+static struct service_context *query(const char *sn)
{
- struct service_context *result = NULL;
standalone_service_registry *registry = standalone_service_registry::instance();
- standalone_service_context *query_result = registry->query(sn, status);
+ standalone_service_context *query_result = registry->query(sn);
- if (query_result) {
+ if (!query_result)
+ return NULL;
- result = query_result->get_service_context();
- }
-
- return result;
+ return query_result->get_service_context();
}
const struct service_location_strategy *standalone_location_strategy(void)
diff --git a/components/service/locator/standalone/standalone_service_context.cpp b/components/service/locator/standalone/standalone_service_context.cpp
index c4fda1e61..181083663 100644
--- a/components/service/locator/standalone/standalone_service_context.cpp
+++ b/components/service/locator/standalone/standalone_service_context.cpp
@@ -8,8 +8,8 @@
#include <cassert>
/* Concrete C service_context methods */
-static rpc_session_handle standalone_service_context_open(void *context, struct rpc_caller **caller);
-static void standalone_service_context_close(void *context, rpc_session_handle session_handle);
+static struct rpc_caller_session *standalone_service_context_open(void *context);
+static void standalone_service_context_close(void *context, rpc_caller_session *session_handle);
static void standalone_service_context_relinquish(void *context);
@@ -62,17 +62,46 @@ void standalone_service_context::deinit()
if (!m_ref_count) do_deinit();
}
-rpc_session_handle standalone_service_context::open(struct rpc_caller **caller)
+struct rpc_caller_session *standalone_service_context::open()
{
- struct rpc_session *session = new rpc_session(m_rpc_interface, m_rpc_buffer_size_override);
- *caller = session->m_rpc_caller;
- return static_cast<rpc_session_handle>(session);
+ rpc_status_t status = RPC_ERROR_INTERNAL;
+ struct rpc_caller_interface *caller = NULL;
+ struct rpc_caller_session *session = NULL;
+
+ caller = (struct rpc_caller_interface *)calloc(1, sizeof(struct rpc_caller_interface));
+ if (!caller)
+ return NULL;
+
+ session = (struct rpc_caller_session *)calloc(1, sizeof(struct rpc_caller_session));
+ if (!session) {
+ free(caller);
+ return NULL;
+ }
+
+ status = direct_caller_init(caller, m_rpc_interface);
+ if (status != RPC_SUCCESS) {
+ free(caller);
+ free(session);
+ return NULL;
+ }
+
+ status = rpc_caller_session_open(session, caller, &m_rpc_interface->uuid, 0, 0x8000);
+ if (status != RPC_SUCCESS) {
+ direct_caller_deinit(caller);
+ free(caller);
+ free(session);
+ return NULL;
+ }
+
+ return session;
}
-void standalone_service_context::close(rpc_session_handle session_handle)
+void standalone_service_context::close(rpc_caller_session *session)
{
- struct rpc_session *session = reinterpret_cast<struct rpc_session*>(session_handle);
- delete session;
+ rpc_caller_session_close(session);
+ direct_caller_deinit(session->caller);
+ free(session->caller);
+ free(session);
}
const std::string &standalone_service_context::get_service_name() const
@@ -85,41 +114,22 @@ struct service_context *standalone_service_context::get_service_context()
return &m_service_context;
}
-void standalone_service_context::set_rpc_interface(rpc_interface *iface)
+void standalone_service_context::set_rpc_interface(rpc_service_interface *iface)
{
m_rpc_interface = iface;
}
-standalone_service_context::rpc_session::rpc_session(
- struct rpc_interface *rpc_interface,
- size_t rpc_buffer_size_override) :
- m_direct_caller(),
- m_rpc_caller()
+static struct rpc_caller_session *standalone_service_context_open(void *context)
{
- m_rpc_caller = (rpc_buffer_size_override) ?
- direct_caller_init(&m_direct_caller, rpc_interface,
- rpc_buffer_size_override, rpc_buffer_size_override) :
- direct_caller_init_default(&m_direct_caller, rpc_interface);
-}
-
-standalone_service_context::rpc_session::~rpc_session()
-{
- direct_caller_deinit(&m_direct_caller);
-}
-
-static rpc_session_handle standalone_service_context_open(void *context, struct rpc_caller **caller)
-{
- rpc_session_handle handle = NULL;
standalone_service_context *this_context = reinterpret_cast<standalone_service_context*>(context);
- if (this_context) {
- handle = this_context->open(caller);
- }
+ if (!this_context)
+ return NULL;
- return handle;
+ return this_context->open();
}
-static void standalone_service_context_close(void *context, rpc_session_handle session_handle)
+static void standalone_service_context_close(void *context, struct rpc_caller_session *session_handle)
{
standalone_service_context *this_context = reinterpret_cast<standalone_service_context*>(context);
diff --git a/components/service/locator/standalone/standalone_service_context.h b/components/service/locator/standalone/standalone_service_context.h
index 64e903d01..f9d1a0d46 100644
--- a/components/service/locator/standalone/standalone_service_context.h
+++ b/components/service/locator/standalone/standalone_service_context.h
@@ -9,8 +9,9 @@
#include <cstddef>
#include <service_locator.h>
-#include <rpc/common/endpoint/rpc_interface.h>
-#include <rpc/direct/direct_caller.h>
+#include "rpc/common/caller/rpc_caller_session.h"
+#include "rpc/common/endpoint/rpc_service_interface.h"
+#include "rpc/direct/direct_caller.h"
#include <string>
class standalone_service_context
@@ -23,35 +24,24 @@ public:
void init();
void deinit();
- rpc_session_handle open(struct rpc_caller **caller);
- void close(rpc_session_handle session_handle);
+ struct rpc_caller_session *open();
+ void close(struct rpc_caller_session *session);
const std::string &get_service_name() const;
struct service_context *get_service_context();
protected:
- void set_rpc_interface(rpc_interface *iface);
+ void set_rpc_interface(rpc_service_interface *iface);
virtual void do_init() {}
virtual void do_deinit() {}
private:
-
- struct rpc_session
- {
- rpc_session(struct rpc_interface *rpc_interface,
- size_t rpc_buffer_size_override);
- ~rpc_session();
-
- struct direct_caller m_direct_caller;
- struct rpc_caller *m_rpc_caller;
- };
-
std::string m_sn;
int m_ref_count;
size_t m_rpc_buffer_size_override;
struct service_context m_service_context;
- struct rpc_interface *m_rpc_interface;
+ struct rpc_service_interface *m_rpc_interface;
};
#endif /* STANDALONE_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/standalone_service_registry.cpp b/components/service/locator/standalone/standalone_service_registry.cpp
index 5625bc046..bbe39a9e7 100644
--- a/components/service/locator/standalone/standalone_service_registry.cpp
+++ b/components/service/locator/standalone/standalone_service_registry.cpp
@@ -51,11 +51,10 @@ standalone_service_context *standalone_service_registry::deregsiter_service_inst
return context;
}
-standalone_service_context *standalone_service_registry::query(const char *sn, int *status)
+standalone_service_context *standalone_service_registry::query(const char *sn)
{
size_t index;
standalone_service_context *context = NULL;
- (void)status;
if (find_context_index(sn, &index)) {
diff --git a/components/service/locator/standalone/standalone_service_registry.h b/components/service/locator/standalone/standalone_service_registry.h
index 7a76aeba6..51da5daa4 100644
--- a/components/service/locator/standalone/standalone_service_registry.h
+++ b/components/service/locator/standalone/standalone_service_registry.h
@@ -29,7 +29,7 @@ public:
void regsiter_service_instance(standalone_service_context *service_context);
standalone_service_context *deregsiter_service_instance(const char *sn);
- standalone_service_context *query(const char *sn, int *status);
+ standalone_service_context *query(const char *sn);
private:
bool find_context_index(const char *sn, size_t *index) const;
diff --git a/components/service/rpmb/backend/component.cmake b/components/service/rpmb/backend/component.cmake
new file mode 100644
index 000000000..5b961a0ec
--- /dev/null
+++ b/components/service/rpmb/backend/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_backend.c"
+)
diff --git a/components/service/rpmb/backend/emulated/component.cmake b/components/service/rpmb/backend/emulated/component.cmake
new file mode 100644
index 000000000..e4dfa1636
--- /dev/null
+++ b/components/service/rpmb/backend/emulated/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_backend_emulated.c"
+)
+
diff --git a/components/service/rpmb/backend/emulated/rpmb_backend_emulated.c b/components/service/rpmb/backend/emulated/rpmb_backend_emulated.c
new file mode 100644
index 000000000..597c1484f
--- /dev/null
+++ b/components/service/rpmb/backend/emulated/rpmb_backend_emulated.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpmb_backend_emulated.h"
+#include "util.h"
+#include "psa/crypto.h"
+#include <stdlib.h>
+#include <string.h>
+
+static void u32_to_rpmb_field(uint32_t u32, uint8_t *rpmb_field)
+{
+ rpmb_field[0] = (u32 >> 24) & 0xff;
+ rpmb_field[1] = (u32 >> 16) & 0xff;
+ rpmb_field[2] = (u32 >> 8) & 0xff;
+ rpmb_field[3] = u32 & 0xff;
+}
+
+static uint32_t u32_from_rpmb_field(const uint8_t *rpmb_field)
+{
+ return (rpmb_field[0] << 24) | (rpmb_field[1] << 16) | (rpmb_field[2] << 8) | rpmb_field[3];
+}
+
+static void u16_to_rpmb_field(uint16_t u16, uint8_t *rpmb_field)
+{
+ rpmb_field[0] = (u16 >> 8) & 0xff;
+ rpmb_field[1] = u16 & 0xff;
+}
+
+static uint16_t u16_from_rpmb_field(const uint8_t *rpmb_field)
+{
+ return (rpmb_field[0] << 8) | rpmb_field[1];
+}
+
+static psa_status_t rpmb_backend_emulated_get_dev_info(
+ void *context, uint32_t dev_id, struct rpmb_dev_info *dev_info)
+{
+ struct rpmb_backend_emulated *backend = (struct rpmb_backend_emulated *)context;
+ static const uint8_t test_cid[] = {
+ /* MID (Manufacturer ID): Micron */
+ 0xfe,
+ /* CBX (Device/BGA): BGA */
+ 0x01,
+ /* OID (OEM/Application ID) */
+ 0x4e,
+ /* PNM (Product name) "MMC04G" */
+ 0x4d, 0x4d, 0x43, 0x30, 0x34, 0x47,
+ /* PRV (Product revision): 4.2 */
+ 0x42,
+ /* PSN (Product serial number) */
+ 0xc8, 0xf6, 0x55, 0x2a,
+ /*
+ * MDT (Manufacturing date):
+ * June, 2014
+ */
+ 0x61,
+ /* (CRC7 (0xA) << 1) | 0x1 */
+ 0x15
+ };
+
+ (void)dev_id;
+
+ memcpy(dev_info->cid, test_cid, sizeof(dev_info->cid));
+ dev_info->rpmb_size_mult = backend->buffer_size / RPMB_SIZE_MULT_UNIT;
+
+ return PSA_SUCCESS;
+}
+
+static void calculate_mac(struct rpmb_backend_emulated *backend,
+ const struct rpmb_data_frame *frames, size_t frame_count, uint8_t *mac)
+{
+ const size_t frame_hash_length =
+ sizeof(struct rpmb_data_frame) - offsetof(struct rpmb_data_frame, data);
+ psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
+ size_t hash_length = 0;
+ size_t i = 0;
+
+ psa_hash_setup(&operation, PSA_ALG_SHA_256);
+ psa_hash_update(&operation, backend->key, sizeof(backend->key));
+
+ for (i = 0; i < frame_count; i++) {
+ /* Hash data, nonce, write counter, address, block, result, req/resp fields */
+ psa_hash_update(&operation, (const uint8_t *)frames[i].data, frame_hash_length);
+ }
+
+ psa_hash_finish(&operation, mac, RPMB_KEY_MAC_SIZE, &hash_length);
+}
+
+static void rpmb_emulated_authentication_key_write(struct rpmb_backend_emulated *backend,
+ const struct rpmb_data_frame *request,
+ struct rpmb_data_frame *response)
+{
+ uint16_t result = RPMB_RES_GENERAL_FAILURE;
+
+ memset(response, 0x00, sizeof(*response));
+
+ if (!backend->key_programmed) {
+ memcpy(backend->key, request->key_mac, sizeof(backend->key));
+ backend->key_programmed = true;
+ result = RPMB_RES_OK;
+ }
+
+ u16_to_rpmb_field(result, response->op_result);
+ u16_to_rpmb_field(RPMB_RESP_TYPE_AUTHENTICATION_KEY_WRITE, response->msg_type);
+}
+
+static void rpmb_emulated_read_write_counter(struct rpmb_backend_emulated *backend,
+ const struct rpmb_data_frame *request,
+ struct rpmb_data_frame *response)
+{
+ uint8_t nonce[RPMB_NONCE_SIZE] = { 0 };
+
+ /*
+ * It is not guarranteed by the RPC layer that the request and response has distinct
+ * memory areas. Thus we need to create a copy of nonce because clearing the response might
+ * clear the request as well.
+ */
+ memcpy(nonce, request->nonce, sizeof(nonce));
+
+ memset(response, 0x00, sizeof(*response));
+ u16_to_rpmb_field(RPMB_RESP_TYPE_READ_WRITE_COUNTER, response->msg_type);
+ u16_to_rpmb_field(RPMB_RES_KEY_NOT_PROGRAMMED, response->op_result);
+
+ if (backend->key_programmed) {
+ memcpy(response->nonce, nonce, RPMB_NONCE_SIZE);
+ u32_to_rpmb_field(backend->write_counter, response->write_counter);
+ u16_to_rpmb_field(RPMB_RES_OK, response->op_result);
+ calculate_mac(backend, response, 1, response->key_mac);
+ }
+}
+
+static uint16_t check_write_request(struct rpmb_backend_emulated *backend,
+ const struct rpmb_data_frame *request)
+{
+ size_t address = 0;
+ uint8_t mac[RPMB_KEY_MAC_SIZE] = { 0 };
+
+ /* Checking as specified in eMMC 6.6.22.4.3 */
+ if (backend->write_counter == 0xffffffff)
+ return RPMB_RES_COUNTER_EXPIRED | RPMB_RES_WRITE_FAILURE;
+
+ if (MUL_OVERFLOW(u16_from_rpmb_field(request->address), RPMB_DATA_SIZE, &address))
+ return RPMB_RES_ADDRESS_FAILURE;
+
+ if (address >= backend->buffer_size)
+ return RPMB_RES_ADDRESS_FAILURE;
+
+ /* Only single block write is supported for now */
+ if (u16_from_rpmb_field(request->block_count) != 1)
+ return RPMB_RES_GENERAL_FAILURE;
+
+ calculate_mac(backend, request, 1, mac);
+ if (memcmp(mac, request->key_mac, sizeof(mac)) != 0)
+ return RPMB_RES_AUTHENTICATION_FAILURE;
+
+ if (backend->write_counter != u32_from_rpmb_field(request->write_counter))
+ return RPMB_RES_COUNTER_FAILURE;
+
+ return RPMB_RES_OK;
+}
+
+static void rpmb_emulated_authenticated_data_write(struct rpmb_backend_emulated *backend,
+ const struct rpmb_data_frame *request,
+ struct rpmb_data_frame *response)
+{
+ uint16_t result = RPMB_RES_KEY_NOT_PROGRAMMED;
+
+ memset(response, 0x00, sizeof(*response));
+ u16_to_rpmb_field(RPMB_RESP_TYPE_AUTHENTICATED_DATA_WRITE, response->msg_type);
+
+ if (backend->key_programmed) {
+ result = check_write_request(backend, request);
+ if (result == RPMB_RES_OK) {
+ size_t address = u16_from_rpmb_field(request->address) * RPMB_DATA_SIZE;
+
+ memcpy(&backend->buffer[address], request->data, sizeof(request->data));
+ backend->write_counter++;
+ }
+
+ memcpy(response->address, request->address, sizeof(response->address));
+ u32_to_rpmb_field(backend->write_counter, response->write_counter);
+ calculate_mac(backend, response, 1, response->key_mac);
+ }
+
+ u16_to_rpmb_field(result, response->op_result);
+
+}
+
+static uint16_t check_read_request(struct rpmb_backend_emulated *backend,
+ const struct rpmb_data_frame *request,
+ size_t *address, size_t *length)
+{
+ uint16_t block_count = 0;
+ size_t end = 0;
+
+ /* Check if start address fits into range */
+ if (MUL_OVERFLOW(u16_from_rpmb_field(request->address), RPMB_DATA_SIZE, address))
+ return RPMB_RES_ADDRESS_FAILURE;
+
+ if (*address >= backend->buffer_size)
+ return RPMB_RES_ADDRESS_FAILURE;
+
+ block_count = u16_from_rpmb_field(request->block_count);
+ if (block_count == 0)
+ return RPMB_RES_GENERAL_FAILURE;
+
+ /* Check if end address fits into range */
+ if (MUL_OVERFLOW(block_count, RPMB_DATA_SIZE, length))
+ return RPMB_RES_ADDRESS_FAILURE;
+
+ if (ADD_OVERFLOW(*address, *length, &end))
+ return RPMB_RES_ADDRESS_FAILURE;
+
+ if (end > backend->buffer_size)
+ return RPMB_RES_ADDRESS_FAILURE;
+
+ return RPMB_RES_OK;
+}
+
+static psa_status_t rpmb_emulated_authenticated_data_read(struct rpmb_backend_emulated *backend,
+ const struct rpmb_data_frame *request,
+ struct rpmb_data_frame *response,
+ size_t *response_count)
+{
+ size_t response_index = 0;
+
+ if (backend->key_programmed) {
+ uint16_t result = RPMB_RES_GENERAL_FAILURE;
+ size_t address = 0;
+ size_t length = 0;
+
+ result = check_read_request(backend, request, &address, &length);
+ if (result == RPMB_RES_OK) {
+ uint16_t block_count = 0;
+ uint16_t i = 0;
+ struct rpmb_data_frame temp = { 0 };
+
+ block_count = u16_from_rpmb_field(request->block_count);
+ if (block_count > *response_count)
+ /*
+ * It is a service level error if available response dataframe count
+ * is less than the requested block count.
+ */
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+
+ for (i = 0; i < block_count; i++) {
+ uint8_t *data = &backend->buffer[address + i * RPMB_DATA_SIZE];
+
+ memset(&temp, 0x00, sizeof(temp));
+ memcpy(temp.data, data, sizeof(temp.data));
+ memcpy(temp.nonce, request->nonce, sizeof(temp.nonce));
+ memcpy(temp.address, request->address, sizeof(temp.address));
+ memcpy(temp.block_count, request->block_count,
+ sizeof(temp.block_count));
+ u16_to_rpmb_field(RPMB_RES_OK, temp.op_result);
+ u16_to_rpmb_field(RPMB_RESP_TYPE_AUTHENTICATED_DATA_READ,
+ temp.msg_type);
+
+ memcpy(&response[i], &temp, sizeof(response[i]));
+ }
+
+ calculate_mac(backend, response, block_count,
+ response[block_count - 1].key_mac);
+ response_index += block_count;
+ }
+ } else {
+ /* Return single data frame with the error code */
+ memset(response, 0x00, sizeof(*response));
+ u16_to_rpmb_field(RPMB_RES_KEY_NOT_PROGRAMMED, response->op_result);
+ u16_to_rpmb_field(RPMB_RESP_TYPE_AUTHENTICATED_DATA_READ, response->msg_type);
+ response_index++;
+ }
+
+ *response_count = response_index;
+
+ return PSA_SUCCESS;
+}
+
+static psa_status_t rpmb_backend_emulated_data_request(
+ void *context, uint32_t dev_id, const struct rpmb_data_frame *request_frames,
+ size_t request_frame_count, struct rpmb_data_frame *response_frames,
+ size_t *response_frame_count)
+{
+ struct rpmb_backend_emulated *backend = (struct rpmb_backend_emulated *)context;
+ size_t req_index = 0;
+ size_t resp_index = 0;
+
+ if (dev_id != 0)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ for (req_index = 0; req_index < request_frame_count; req_index++) {
+ const struct rpmb_data_frame *request = &request_frames[req_index];
+
+ switch (u16_from_rpmb_field(request->msg_type)) {
+ case RPMB_REQ_TYPE_AUTHENTICATION_KEY_WRITE:
+ rpmb_emulated_authentication_key_write(backend, request, &backend->result);
+ break;
+
+ case RPMB_REQ_TYPE_READ_WRITE_COUNTER:
+ if (resp_index < *response_frame_count) {
+ struct rpmb_data_frame *response = &response_frames[resp_index++];
+
+ rpmb_emulated_read_write_counter(backend, request, response);
+ } else {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case RPMB_REQ_TYPE_AUTHENTICATED_DATA_WRITE:
+ rpmb_emulated_authenticated_data_write(backend, request, &backend->result);
+ break;
+
+ case RPMB_REQ_TYPE_AUTHENTICATED_DATA_READ:
+ if (resp_index < *response_frame_count) {
+ struct rpmb_data_frame *response = &response_frames[resp_index];
+ size_t response_count = *response_frame_count - resp_index;
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+ status = rpmb_emulated_authenticated_data_read(
+ backend, request, response, &response_count);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ resp_index += response_count;
+ } else {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case RPMB_REQ_TYPE_RESULT_READ_REQUEST:
+ if (resp_index < *response_frame_count) {
+ struct rpmb_data_frame *response = &response_frames[resp_index++];
+
+ memcpy(response, &backend->result, sizeof(*response));
+ } else {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ default:
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ *response_frame_count = resp_index;
+
+ return PSA_SUCCESS;
+}
+
+struct rpmb_backend *rpmb_backend_emulated_init(struct rpmb_backend_emulated *context,
+ uint8_t size_mult)
+{
+ static const struct rpmb_backend_interface interface = {
+ rpmb_backend_emulated_get_dev_info,
+ rpmb_backend_emulated_data_request,
+ };
+
+ if (!context || !size_mult)
+ return NULL;
+
+ context->buffer_size = size_mult * RPMB_SIZE_MULT_UNIT;
+ context->buffer = calloc(1, context->buffer_size);
+ if (!context->buffer)
+ return NULL;
+
+ context->backend.context = context;
+ context->backend.interface = &interface;
+
+ return &context->backend;
+}
+
+void rpmb_backend_emulated_deinit(struct rpmb_backend_emulated *context)
+{
+ free(context->buffer);
+}
diff --git a/components/service/rpmb/backend/emulated/rpmb_backend_emulated.h b/components/service/rpmb/backend/emulated/rpmb_backend_emulated.h
new file mode 100644
index 000000000..c13a6dd3d
--- /dev/null
+++ b/components/service/rpmb/backend/emulated/rpmb_backend_emulated.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_BACKEND_EMULATED
+#define RPMB_BACKEND_EMULATED
+
+#include "../rpmb_backend.h"
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Emulated RPMB backend
+ *
+ * This backend uses a memory allocated buffer for storing data and it emulates
+ * all the necessary data frame checks.
+ */
+struct rpmb_backend_emulated {
+ struct rpmb_backend backend;
+ uint8_t *buffer;
+ size_t buffer_size;
+ uint8_t key[RPMB_KEY_MAC_SIZE];
+ bool key_programmed;
+ uint32_t write_counter;
+ struct rpmb_data_frame result;
+};
+
+/**
+ * \brief Initialize emulated RPMB backend
+ *
+ * \param context[in] Backend context
+ * \param size_mult[in] Size of the RPMB in 128kB units
+ * \return struct rpmb_backend*
+ */
+struct rpmb_backend *rpmb_backend_emulated_init(struct rpmb_backend_emulated *context,
+ uint8_t size_mult);
+
+/**
+ * \brief Deinitialize emulated RPMB backend
+ *
+ * \param context[in] Backend context
+ */
+void rpmb_backend_emulated_deinit(struct rpmb_backend_emulated *context);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* RPMB_BACKEND_EMULATED */
diff --git a/components/service/rpmb/backend/mock/component.cmake b/components/service/rpmb/backend/mock/component.cmake
new file mode 100644
index 000000000..b75d6e35c
--- /dev/null
+++ b/components/service/rpmb/backend/mock/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_backend_mock.cpp"
+ )
diff --git a/components/service/rpmb/backend/mock/rpmb_backend_mock.cpp b/components/service/rpmb/backend/mock/rpmb_backend_mock.cpp
new file mode 100644
index 000000000..83bde95f1
--- /dev/null
+++ b/components/service/rpmb/backend/mock/rpmb_backend_mock.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include "rpmb_backend_mock.h"
+
+void rpmb_backend_mock_expect_get_dev_info(void *context, uint32_t dev_id,
+ const struct rpmb_dev_info *dev_info,
+ psa_status_t result)
+{
+ mock().expectOneCall("get_dev_info").
+ onObject(context).
+ withUnsignedIntParameter("dev_id", dev_id).
+ withOutputParameterReturning("dev_info", dev_info, sizeof(*dev_info)).
+ andReturnValue(result);
+}
+
+static psa_status_t rpmb_backend_mock_get_dev_info(void *context, uint32_t dev_id,
+ struct rpmb_dev_info *dev_info)
+{
+ return mock().actualCall("get_dev_info").
+ onObject(context).
+ withUnsignedIntParameter("dev_id", dev_id).
+ withOutputParameter("dev_info", dev_info).
+ returnIntValue();
+}
+
+void rpmb_backend_mock_expect_data_request(
+ void *context, uint32_t dev_id, const struct rpmb_data_frame *request_frames,
+ size_t request_frame_count, const struct rpmb_data_frame *response_frames,
+ size_t response_frame_count_in, size_t *response_frame_count_out, psa_status_t result)
+{
+ size_t request_size = sizeof(*request_frames) * request_frame_count;
+ size_t response_size = sizeof(*response_frames) * (*response_frame_count_out);
+
+ mock().expectOneCall("data_request").
+ onObject(context).
+ withUnsignedIntParameter("dev_id", dev_id).
+ withMemoryBufferParameter("request_frames", (const unsigned char *)request_frames,
+ request_size).
+ withUnsignedIntParameter("request_frame_count", request_frame_count).
+ withOutputParameterReturning("response_frames", response_frames, response_size).
+ withUnsignedIntParameter("response_frame_count_in", response_frame_count_in).
+ withOutputParameterReturning("response_frame_count_out", response_frame_count_out,
+ sizeof(*response_frame_count_out)).
+ andReturnValue(result);
+}
+
+static psa_status_t rpmb_backend_mock_data_request(
+ void *context, uint32_t dev_id, const struct rpmb_data_frame *request_frames,
+ size_t request_frame_count, struct rpmb_data_frame *response_frames,
+ size_t *response_frame_count)
+{
+ size_t request_size = sizeof(*request_frames) * request_frame_count;
+
+ return mock().actualCall("data_request").
+ onObject(context).
+ withUnsignedIntParameter("dev_id", dev_id).
+ withMemoryBufferParameter("request_frames", (const unsigned char *)request_frames,
+ request_size).
+ withUnsignedIntParameter("request_frame_count", request_frame_count).
+ withOutputParameter("response_frames", response_frames).
+ withUnsignedIntParameter("response_frame_count_in", *response_frame_count).
+ withOutputParameter("response_frame_count_out", response_frame_count).
+ returnIntValue();
+}
+
+struct rpmb_backend *rpmb_backend_mock_init(struct rpmb_backend_mock *context)
+{
+ static const struct rpmb_backend_interface interface = {
+ rpmb_backend_mock_get_dev_info,
+ rpmb_backend_mock_data_request,
+ };
+
+ if (!context)
+ return NULL;
+
+ context->backend.context = context;
+ context->backend.interface = &interface;
+
+ return &context->backend;
+}
+
+void rpmb_backend_mock_deinit(struct rpmb_backend_mock *context)
+{
+ *context = (struct rpmb_backend_mock){ 0 };
+}
diff --git a/components/service/rpmb/backend/mock/rpmb_backend_mock.h b/components/service/rpmb/backend/mock/rpmb_backend_mock.h
new file mode 100644
index 000000000..1268d4296
--- /dev/null
+++ b/components/service/rpmb/backend/mock/rpmb_backend_mock.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_BACKEND_MOCK_H_
+#define RPMB_BACKEND_MOCK_H_
+
+#include "../rpmb_backend.h"
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Mock RPMB backend
+ *
+ * Backend for testing purposes
+ */
+struct rpmb_backend_mock {
+ struct rpmb_backend backend;
+};
+
+struct rpmb_backend *rpmb_backend_mock_init(struct rpmb_backend_mock *context);
+void rpmb_backend_mock_deinit(struct rpmb_backend_mock *context);
+
+void rpmb_backend_mock_expect_get_dev_info(void *context, uint32_t dev_id,
+ const struct rpmb_dev_info *dev_info,
+ psa_status_t result);
+
+void rpmb_backend_mock_expect_data_request(
+ void *context, uint32_t dev_id, const struct rpmb_data_frame *request_frames,
+ size_t request_frame_count, const struct rpmb_data_frame *response_frames,
+ size_t response_frame_count_in, size_t *response_frame_count_out, psa_status_t result);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* RPMB_BACKEND_MOCK_H_ */
diff --git a/components/service/rpmb/backend/mock/test/component.cmake b/components/service/rpmb/backend/mock/test/component.cmake
new file mode 100644
index 000000000..86506bf25
--- /dev/null
+++ b/components/service/rpmb/backend/mock/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/test_rpmb_backend_mock.cpp"
+ )
diff --git a/components/service/rpmb/backend/mock/test/test_rpmb_backend_mock.cpp b/components/service/rpmb/backend/mock/test/test_rpmb_backend_mock.cpp
new file mode 100644
index 000000000..594ba3cc7
--- /dev/null
+++ b/components/service/rpmb/backend/mock/test/test_rpmb_backend_mock.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include "../rpmb_backend_mock.h"
+#include <string.h>
+
+TEST_GROUP(rpmb_backend_mock) {
+ TEST_SETUP()
+ {
+ backend = rpmb_backend_mock_init(&mock_backend);
+ }
+
+ TEST_TEARDOWN()
+ {
+ rpmb_backend_mock_deinit(&mock_backend);
+ }
+
+ struct rpmb_backend *backend;
+ struct rpmb_backend_mock mock_backend;
+ const uint32_t dev_id = 1;
+};
+
+TEST(rpmb_backend_mock, get_dev_info)
+{
+ const struct rpmb_dev_info expected_dev_info = {
+ .cid = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ .rpmb_size_mult = 100
+ };
+ struct rpmb_dev_info dev_info = { 0 };
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &expected_dev_info, PSA_SUCCESS);
+
+ status = rpmb_backend_get_dev_info(backend, dev_id, &dev_info);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ MEMCMP_EQUAL(&expected_dev_info, &dev_info, sizeof(expected_dev_info));
+}
+
+TEST(rpmb_backend_mock, data_request)
+{
+ struct rpmb_data_frame request_frames[2];
+ struct rpmb_data_frame expected_response_frames[3];
+ struct rpmb_data_frame response_frames[3] = { 0 };
+ size_t expected_response_frame_count = 3;
+ size_t response_frame_count = 4;
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+ memset(request_frames, 0x11, sizeof(request_frames));
+ memset(expected_response_frames, 0x22, sizeof(response_frames));
+
+ rpmb_backend_mock_expect_data_request(backend, dev_id,
+ request_frames, 2,
+ expected_response_frames, 4, &expected_response_frame_count,
+ PSA_SUCCESS);
+
+ status = rpmb_backend_data_request(backend, dev_id, request_frames, 2,
+ response_frames, &response_frame_count);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(expected_response_frame_count, response_frame_count);
+ MEMCMP_EQUAL(&expected_response_frames, &response_frames, sizeof(expected_response_frames));
+} \ No newline at end of file
diff --git a/components/service/rpmb/backend/rpmb_backend.c b/components/service/rpmb/backend/rpmb_backend.c
new file mode 100644
index 000000000..fb5913cd6
--- /dev/null
+++ b/components/service/rpmb/backend/rpmb_backend.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpmb_backend.h"
+
+int rpmb_backend_get_dev_info(struct rpmb_backend *instance, uint32_t dev_id,
+ struct rpmb_dev_info *dev_info)
+{
+ return instance->interface->get_dev_info(instance->context, dev_id, dev_info);
+}
+
+int rpmb_backend_data_request(struct rpmb_backend *instance, uint32_t dev_id,
+ const struct rpmb_data_frame *request_frames,
+ size_t request_frame_count,
+ struct rpmb_data_frame *response_frames, size_t *response_frame_count)
+{
+ return instance->interface->data_request(instance->context, dev_id, request_frames,
+ request_frame_count, response_frames,
+ response_frame_count);
+}
diff --git a/components/service/rpmb/backend/rpmb_backend.h b/components/service/rpmb/backend/rpmb_backend.h
new file mode 100644
index 000000000..5800bb75d
--- /dev/null
+++ b/components/service/rpmb/backend/rpmb_backend.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_BACKEND_H_
+#define RPMB_BACKEND_H_
+
+#include "psa/error.h"
+#include "compiler.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief RPMB request/response message types
+ *
+ * Defined in eMMC 4.5 (JESD84-B51) standard's Table 18.
+ */
+#define RPMB_REQ_TYPE_AUTHENTICATION_KEY_WRITE (0x0001)
+#define RPMB_REQ_TYPE_READ_WRITE_COUNTER (0x0002)
+#define RPMB_REQ_TYPE_AUTHENTICATED_DATA_WRITE (0x0003)
+#define RPMB_REQ_TYPE_AUTHENTICATED_DATA_READ (0x0004)
+#define RPMB_REQ_TYPE_RESULT_READ_REQUEST (0x0005)
+#define RPMB_REQ_TYPE_DEVICE_CONFIG_WRITE (0x0006)
+#define RPMB_REQ_TYPE_DEVICE_CONFIG_READ (0x0007)
+
+#define RPMB_RESP_TYPE_AUTHENTICATION_KEY_WRITE (0x0100)
+#define RPMB_RESP_TYPE_READ_WRITE_COUNTER (0x0200)
+#define RPMB_RESP_TYPE_AUTHENTICATED_DATA_WRITE (0x0300)
+#define RPMB_RESP_TYPE_AUTHENTICATED_DATA_READ (0x0400)
+#define RPMB_RESP_TYPE_DEVICE_CONFIG_WRITE (0x0600)
+#define RPMB_RESP_TYPE_DEVICE_CONFIG_READ (0x0700)
+
+/**
+ * \brief RPMB operation results
+ *
+ * Defined in eMMC 4.5 (JESD84-B51) standard's Table 20.
+ */
+#define RPMB_RES_OK (0x0000)
+#define RPMB_RES_GENERAL_FAILURE (0x0001)
+#define RPMB_RES_AUTHENTICATION_FAILURE (0x0002)
+#define RPMB_RES_COUNTER_FAILURE (0x0003)
+#define RPMB_RES_ADDRESS_FAILURE (0x0004)
+#define RPMB_RES_WRITE_FAILURE (0x0005)
+#define RPMB_RES_READ_FAILURE (0x0006)
+#define RPMB_RES_KEY_NOT_PROGRAMMED (0x0007)
+
+#define RPMB_RES_COUNTER_EXPIRED (0x0080)
+
+/**
+ * \brief Additional RPMB related definitions
+ */
+#define RPMB_EMMC_CID_SIZE (16)
+#define RPMB_CID_PRODUCT_REVISION (9)
+#define RPMB_CID_CRC7 (15)
+#define RPMB_STUFF_DATA_SIZE (196)
+#define RPMB_KEY_MAC_SIZE (32)
+#define RPMB_DATA_SIZE (256)
+#define RPMB_NONCE_SIZE (16)
+#define RPMB_SIZE_MULT_UNIT (128 * 1024)
+
+/**
+ * \brief RPMB device info
+ *
+ * The RPMB device info structure contains the Device Identification (CID) and RPMB_SIZE_MULT
+ * registers' value. The CID value is unique to each RPMB device and it can be involved into the
+ * authentication key generation process. The RPMB_SIZE_MULT value indicates the size of the RPMB
+ * in 128kB units.
+ */
+struct rpmb_dev_info {
+ uint8_t cid[RPMB_EMMC_CID_SIZE];
+ uint8_t rpmb_size_mult;
+} __packed;
+
+/**
+ * \brief RPMB data frame
+ *
+ * Defined in eMMC 4.5 (JESD84-B51) standard's Table 17.
+ */
+struct rpmb_data_frame {
+ uint8_t stuff_bytes[RPMB_STUFF_DATA_SIZE];
+ uint8_t key_mac[RPMB_KEY_MAC_SIZE];
+ uint8_t data[RPMB_DATA_SIZE];
+ uint8_t nonce[RPMB_NONCE_SIZE];
+ uint8_t write_counter[4];
+ uint8_t address[2];
+ uint8_t block_count[2];
+ uint8_t op_result[2];
+ uint8_t msg_type[2];
+} __packed;
+
+/**
+ * \brief RPMB backend interface
+ *
+ * The structure defines the function interface that the backend has to implement in order to
+ * provide hardware access to the RPMB device.
+ */
+struct rpmb_backend_interface {
+ psa_status_t (*get_dev_info)(void *context, uint32_t dev_id,
+ struct rpmb_dev_info *dev_info);
+
+ psa_status_t (*data_request)(void *context, uint32_t dev_id,
+ const struct rpmb_data_frame *request_frames,
+ size_t request_frame_count,
+ struct rpmb_data_frame *response_frames,
+ size_t *response_frame_count);
+};
+
+/**
+ * \brief RPMB backend
+ *
+ * Generic object for storing the RPMB backend interface and the implementation specific context.
+ */
+struct rpmb_backend {
+ void *context;
+ const struct rpmb_backend_interface *interface;
+};
+
+/**
+ * \brief Query RPMB device info from the device
+ *
+ * \return Pointer to the base block_store or NULL on failure
+ * \param[in] instance RPMB backend instance
+ * \param[in] dev_id RPMB device ID
+ * \param[out] dev_info Device info
+ * \return psa_status_t
+ */
+psa_status_t rpmb_backend_get_dev_info(struct rpmb_backend *instance, uint32_t dev_id,
+ struct rpmb_dev_info *dev_info);
+
+/**
+ * \brief Write and read data frames into and from the RPMB device.
+ *
+ * \param[in] instance RPMB backend instance
+ * \param[in] dev_id RPMB device ID
+ * \param[in] request_frames Request data frames
+ * \param[in] request_frame_count Request data frame count
+ * \param[out] response_frames Response data frames
+ * \param[inout] response_frame_count in: maximal response data frame count, out: actual response
+ * data frame count
+ * \return psa_status_t
+ */
+psa_status_t rpmb_backend_data_request(struct rpmb_backend *instance, uint32_t dev_id,
+ const struct rpmb_data_frame *request_frames,
+ size_t request_frame_count,
+ struct rpmb_data_frame *response_frames,
+ size_t *response_frame_count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_BACKEND_H_ */
diff --git a/components/service/rpmb/client/component.cmake b/components/service/rpmb/client/component.cmake
new file mode 100644
index 000000000..2a04a3b05
--- /dev/null
+++ b/components/service/rpmb/client/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_client.c"
+)
diff --git a/components/service/rpmb/client/rpmb_client.c b/components/service/rpmb/client/rpmb_client.c
new file mode 100644
index 000000000..56bc961d2
--- /dev/null
+++ b/components/service/rpmb/client/rpmb_client.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpmb_client.h"
+#include "protocols/service/rpmb/packed-c/rpmb_proto.h"
+#include "util.h"
+#include <string.h>
+
+static psa_status_t rpmb_client_get_dev_info(void *context, uint32_t dev_id,
+ struct rpmb_dev_info *dev_info)
+{
+ struct rpmb_client *this_context = (struct rpmb_client *)context;
+ struct rpmb_request_get_dev_info *request_desc = NULL;
+ struct rpmb_response_get_dev_info *response_desc = NULL;
+ size_t response_length = 0;
+ rpc_call_handle handle = 0;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ service_status_t service_status = 0;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+
+ handle = rpc_caller_session_begin(this_context->session, (uint8_t **)&request_desc,
+ sizeof(*request_desc), sizeof(*response_desc));
+ if (!handle)
+ return PSA_ERROR_GENERIC_ERROR;
+
+ request_desc->dev_id = dev_id;
+
+ rpc_status = rpc_caller_session_invoke(handle, TS_RPMB_OPCODE_GET_DEV_INFO,
+ (uint8_t **)&response_desc, &response_length,
+ &service_status);
+ if (rpc_status != RPC_SUCCESS || response_length != sizeof(*response_desc))
+ goto session_end;
+
+ psa_status = service_status;
+
+ if (psa_status == PSA_SUCCESS)
+ *dev_info = response_desc->dev_info;
+
+session_end:
+ rpc_status = rpc_caller_session_end(handle);
+ if (psa_status == PSA_SUCCESS && rpc_status != RPC_SUCCESS)
+ psa_status = PSA_ERROR_GENERIC_ERROR;
+
+ return psa_status;
+}
+
+static bool calculate_size(size_t header_size, uint32_t frame_count, size_t *frames_size,
+ size_t *total_size)
+{
+ /* Calculating [data frame count] * [data frame size] + [header size] */
+
+ if (MUL_OVERFLOW(frame_count, sizeof(struct rpmb_data_frame), frames_size))
+ return false;
+
+ if (ADD_OVERFLOW(*frames_size, header_size, total_size))
+ return false;
+
+ return true;
+}
+
+static psa_status_t rpmb_client_data_request(void *context, uint32_t dev_id,
+ const struct rpmb_data_frame *request_frames,
+ size_t request_frame_count,
+ struct rpmb_data_frame *response_frames,
+ size_t *response_frame_count)
+{
+ struct rpmb_client *this_context = (struct rpmb_client *)context;
+ /* Request */
+ struct rpmb_request_data_request *request_desc = NULL;
+ size_t request_frames_length = 0;
+ size_t request_length = 0;
+ /* Response */
+ struct rpmb_response_data_request *response_desc = NULL;
+ size_t response_frames_max_length = 0;
+ size_t response_frames_length = 0;
+ size_t response_max_length = 0;
+ size_t response_length = 0;
+ rpc_call_handle handle = 0;
+ /* Status */
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ service_status_t service_status = 0;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+
+ /* Calculating request lengths */
+ if (!calculate_size(sizeof(*request_desc), request_frame_count,
+ &request_frames_length, &request_length))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ /* Calculating response lengths */
+ if (!calculate_size(sizeof(*response_desc), *response_frame_count,
+ &response_frames_max_length, &response_max_length))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ handle = rpc_caller_session_begin(this_context->session, (uint8_t **)&request_desc,
+ request_length, response_max_length);
+ if (!handle)
+ goto out;
+
+ request_desc->dev_id = dev_id;
+ request_desc->request_frame_count = request_frame_count;
+ request_desc->max_response_frame_count = *response_frame_count;
+ memcpy(request_desc->request_frames, request_frames, request_frames_length);
+
+ rpc_status = rpc_caller_session_invoke(handle, TS_RPMB_OPCODE_DATA_REQUEST,
+ (uint8_t **)&response_desc, &response_length,
+ &service_status);
+ if (rpc_status != RPC_SUCCESS)
+ goto session_end;
+
+ /* Checking if the response length is too small or large */
+ if (response_length < sizeof(*response_desc) || response_length > response_max_length)
+ goto session_end;
+
+ /* Checking if the response data frames have the expected length */
+ if (!calculate_size(sizeof(*response_desc), response_desc->response_frame_count,
+ &response_frames_length, &response_max_length))
+ goto session_end;
+
+ if (response_length != response_max_length)
+ goto session_end;
+
+ psa_status = service_status;
+
+ if (psa_status == PSA_SUCCESS) {
+ memcpy(response_frames, response_desc->response_frames, response_frames_length);
+ *response_frame_count = response_desc->response_frame_count;
+ } else {
+ *response_frame_count = 0;
+ }
+
+session_end:
+ rpc_status = rpc_caller_session_end(handle);
+ if (psa_status == PSA_SUCCESS && rpc_status != RPC_SUCCESS)
+ psa_status = PSA_ERROR_GENERIC_ERROR;
+
+out:
+ return psa_status;
+}
+
+struct rpmb_backend *rpmb_client_init(struct rpmb_client *context,
+ struct rpc_caller_session *session)
+{
+ static const struct rpmb_backend_interface interface = {
+ rpmb_client_get_dev_info,
+ rpmb_client_data_request
+ };
+
+ if (!context || !session)
+ return NULL;
+
+ context->backend.context = context;
+ context->backend.interface = &interface;
+ context->session = session;
+
+ return &context->backend;
+}
+
+void rpmb_client_deinit(struct rpmb_client *context)
+{
+ (void)context;
+}
diff --git a/components/service/rpmb/client/rpmb_client.h b/components/service/rpmb/client/rpmb_client.h
new file mode 100644
index 000000000..466ba78d3
--- /dev/null
+++ b/components/service/rpmb/client/rpmb_client.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_CLIENT_H_
+#define RPMB_CLIENT_H_
+
+#include "components/service/rpmb/backend/rpmb_backend.h"
+#include "components/rpc/common/caller/rpc_caller_session.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief RPMB client
+ *
+ * The RPMB client provides and RPMB backend via accessing a remove backend through RPC.
+ */
+struct rpmb_client {
+ struct rpmb_backend backend;
+ struct rpc_caller_session *session;
+};
+
+/**
+ * \brief Initialize RPMB client
+ *
+ * \param context[in] RPMB client context
+ * \param session[in] RPC caller session
+ * \return struct rpmb_backend* RPMB backend or NULL on error
+ */
+struct rpmb_backend *rpmb_client_init(struct rpmb_client *context,
+ struct rpc_caller_session *session);
+
+/**
+ * \brief Deinitialize RPMB client
+ *
+ * \param context[in] RPMB client context
+ */
+void rpmb_client_deinit(struct rpmb_client *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_CLIENT_H_ */
diff --git a/components/service/rpmb/frontend/component.cmake b/components/service/rpmb/frontend/component.cmake
new file mode 100644
index 000000000..d3dd4bfe1
--- /dev/null
+++ b/components/service/rpmb/frontend/component.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_frontend.c"
+)
+
+set(RPMB_WRITE_KEY FALSE CACHE BOOL "Enable RPMB Authentication Key Write")
+
+if (RPMB_WRITE_KEY)
+set(_RPMB_WRITE_KEY 1)
+else()
+set(_RPMB_WRITE_KEY 0)
+endif()
+
+target_compile_definitions(${TGT} PRIVATE RPMB_WRITE_KEY=${_RPMB_WRITE_KEY})
diff --git a/components/service/rpmb/frontend/platform/default/component.cmake b/components/service/rpmb/frontend/platform/default/component.cmake
new file mode 100644
index 000000000..b9b886046
--- /dev/null
+++ b/components/service/rpmb/frontend/platform/default/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_platform_default.c"
+)
diff --git a/components/service/rpmb/frontend/platform/default/rpmb_platform_default.c b/components/service/rpmb/frontend/platform/default/rpmb_platform_default.c
new file mode 100644
index 000000000..5b73a9328
--- /dev/null
+++ b/components/service/rpmb/frontend/platform/default/rpmb_platform_default.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpmb_platform_default.h"
+#include "psa/crypto.h"
+
+static psa_status_t rpmb_platform_derive_key(void *context, const uint8_t *data,
+ size_t data_length, uint8_t *key, size_t key_length)
+{
+ psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ size_t hash_length = 0;
+ const uint8_t dummy_huk[] = {
+ 0x32, 0x2b, 0x78, 0x27, 0xa3, 0x08, 0xcb, 0x5e,
+ 0xb4, 0x12, 0x0b, 0xab, 0x96, 0xd4, 0x3d, 0x4e,
+ 0x7b, 0xc4, 0x46, 0x46, 0xad, 0x93, 0xe9, 0x03,
+ 0x28, 0x47, 0xe8, 0xb6, 0x2c, 0xec, 0x5f, 0x14
+ };
+
+ (void)context;
+
+ status = psa_hash_setup(&operation, PSA_ALG_SHA_256);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ status = psa_hash_update(&operation, dummy_huk, sizeof(dummy_huk));
+ if (status != PSA_SUCCESS)
+ return status;
+
+ status = psa_hash_update(&operation, data, data_length);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ status = psa_hash_finish(&operation, key, key_length, &hash_length);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ if (hash_length != key_length)
+ return PSA_ERROR_INVALID_SIGNATURE;
+
+ return PSA_SUCCESS;
+}
+
+static psa_status_t rpmb_platform_get_nonce(void *context, uint8_t *nonce, size_t nonce_length)
+{
+ (void)context;
+
+ return psa_generate_random(nonce, nonce_length);
+}
+
+static psa_status_t rpmb_platform_calculate_mac(void *context, const uint8_t *key,
+ size_t key_length,
+ const struct rpmb_data_frame *frames,
+ size_t frame_count, uint8_t *mac, size_t mac_length)
+{
+ /* Length of the data frame from the start of the data field to the end of the frame */
+ const size_t frame_hash_length =
+ sizeof(struct rpmb_data_frame) - offsetof(struct rpmb_data_frame, data);
+ psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ size_t hash_length = 0;
+ size_t i = 0;
+
+ (void)context;
+
+ status = psa_hash_setup(&operation, PSA_ALG_SHA_256);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ status = psa_hash_update(&operation, key, key_length);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ for (i = 0; i < frame_count; i++) {
+ /* Hash data, nonce, write counter, address, block, result, req/resp fields */
+ status = psa_hash_update(&operation, (const uint8_t *)frames[i].data,
+ frame_hash_length);
+ if (status != PSA_SUCCESS)
+ return status;
+ }
+
+ status = psa_hash_finish(&operation, mac, mac_length, &hash_length);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ if (hash_length != mac_length)
+ return PSA_ERROR_INVALID_SIGNATURE;
+
+ return PSA_SUCCESS;
+}
+
+struct rpmb_platform *rpmb_platform_default_init(struct rpmb_platform_default *context)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ static struct rpmb_platform_interface interface = {
+ rpmb_platform_derive_key,
+ rpmb_platform_get_nonce,
+ rpmb_platform_calculate_mac
+ };
+
+ if (!context)
+ return NULL;
+
+ status = psa_crypto_init();
+ if (status != PSA_SUCCESS)
+ return NULL;
+
+ context->platform.context = context;
+ context->platform.interface = &interface;
+
+ return &context->platform;
+}
+
+void rpmc_platform_default_deinit(struct rpmb_platform_default *context)
+{
+ *context = (struct rpmb_platform_default) { 0 };
+}
diff --git a/components/service/rpmb/frontend/platform/default/rpmb_platform_default.h b/components/service/rpmb/frontend/platform/default/rpmb_platform_default.h
new file mode 100644
index 000000000..49a7106e9
--- /dev/null
+++ b/components/service/rpmb/frontend/platform/default/rpmb_platform_default.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_PLATFORM_DEFAULT_H_
+#define RPMB_PLATFORM_DEFAULT_H_
+
+#include "../../rpmb_frontend.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rpmb_platform_default {
+ struct rpmb_platform platform;
+};
+
+struct rpmb_platform *rpmb_platform_default_init(struct rpmb_platform_default *context);
+
+void rpmc_platform_default_deinit(struct rpmb_platform_default *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_PLATFORM_DEFAULT_H_ */
diff --git a/components/service/rpmb/frontend/platform/mock/component.cmake b/components/service/rpmb/frontend/platform/mock/component.cmake
new file mode 100644
index 000000000..f7fc45ac2
--- /dev/null
+++ b/components/service/rpmb/frontend/platform/mock/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_platform_mock.cpp"
+)
diff --git a/components/service/rpmb/frontend/platform/mock/rpmb_platform_mock.cpp b/components/service/rpmb/frontend/platform/mock/rpmb_platform_mock.cpp
new file mode 100644
index 000000000..8a81c4a6e
--- /dev/null
+++ b/components/service/rpmb/frontend/platform/mock/rpmb_platform_mock.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <CppUTestExt/MockSupport.h>
+#include "rpmb_platform_mock.h"
+
+void rpmb_platform_mock_expect_derive_key(void *context, const uint8_t *data, size_t data_length,
+ const uint8_t *key, size_t key_length,
+ psa_status_t result)
+{
+ mock().expectOneCall("derive_key").
+ onObject(context).
+ withMemoryBufferParameter("data", data, data_length).
+ withOutputParameterReturning("key", key, key_length).
+ withUnsignedIntParameter("key_length", key_length).
+ andReturnValue(result);
+}
+
+static psa_status_t rpmb_platform_derive_key(void *context, const uint8_t *data, size_t data_length,
+ uint8_t *key, size_t key_length)
+{
+ return mock().actualCall("derive_key").
+ onObject(context).
+ withMemoryBufferParameter("data", data, data_length).
+ withOutputParameter("key", key).
+ withUnsignedIntParameter("key_length", key_length).
+ returnIntValue();
+}
+
+void rpmb_platform_mock_expect_get_nonce(void *context, const uint8_t *nonce, size_t nonce_length,
+ psa_status_t result)
+{
+ mock().expectOneCall("get_nonce").
+ onObject(context).
+ withOutputParameterReturning("nonce", nonce, nonce_length).
+ withUnsignedIntParameter("nonce_length", nonce_length).
+ andReturnValue(result);
+}
+
+static psa_status_t rpmb_platform_get_nonce(void *context, uint8_t *nonce, size_t nonce_length)
+{
+ return mock().actualCall("get_nonce").
+ onObject(context).
+ withOutputParameter("nonce", nonce).
+ withUnsignedIntParameter("nonce_length", nonce_length).
+ returnIntValue();
+}
+
+void rpmb_platform_mock_expect_calculate_mac(void *context, const uint8_t *key, size_t key_length,
+ const struct rpmb_data_frame *frames,
+ size_t frame_count, const uint8_t *mac,
+ size_t mac_length, psa_status_t result)
+{
+ mock().expectOneCall("calculate_mac").
+ onObject(context).
+ withMemoryBufferParameter("key", key, key_length).
+ withMemoryBufferParameter("frames", (const unsigned char *)frames, sizeof(*frames) * frame_count).
+ withOutputParameterReturning("mac", mac, mac_length).
+ withUnsignedIntParameter("mac_length", mac_length).
+ andReturnValue(result);
+}
+
+static psa_status_t rpmb_platform_calculate_mac(void *context, const uint8_t *key,
+ size_t key_length,
+ const struct rpmb_data_frame *frames,
+ size_t frame_count, uint8_t *mac, size_t mac_length)
+{
+ return mock().actualCall("calculate_mac").
+ onObject(context).
+ withMemoryBufferParameter("key", key, key_length).
+ withMemoryBufferParameter("frames", (const unsigned char *)frames, sizeof(*frames) * frame_count).
+ withOutputParameter("mac", mac).
+ withUnsignedIntParameter("mac_length", mac_length).
+ returnIntValue();
+}
+
+struct rpmb_platform *rpmb_platform_mock_init(struct rpmb_platform_mock *context)
+{
+ static struct rpmb_platform_interface interface = {
+ rpmb_platform_derive_key,
+ rpmb_platform_get_nonce,
+ rpmb_platform_calculate_mac
+ };
+
+ if (!context)
+ return NULL;
+
+ context->platform.context = context;
+ context->platform.interface = &interface;
+
+ return &context->platform;
+}
+
+void rpmb_platform_mock_deinit(struct rpmb_platform_mock *context)
+{
+ *context = (struct rpmb_platform_mock) { 0 };
+}
diff --git a/components/service/rpmb/frontend/platform/mock/rpmb_platform_mock.h b/components/service/rpmb/frontend/platform/mock/rpmb_platform_mock.h
new file mode 100644
index 000000000..b3007537e
--- /dev/null
+++ b/components/service/rpmb/frontend/platform/mock/rpmb_platform_mock.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_PLATFORM_MOCK_H_
+#define RPMB_PLATFORM_MOCK_H_
+
+#include "../../rpmb_frontend.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Mock RPMB platform
+ *
+ * RPMB platform for testing purposes
+ */
+struct rpmb_platform_mock {
+ struct rpmb_platform platform;
+};
+
+struct rpmb_platform *rpmb_platform_mock_init(struct rpmb_platform_mock *context);
+void rpmb_platform_mock_deinit(struct rpmb_platform_mock *context);
+
+void rpmb_platform_mock_expect_derive_key(void *context, const uint8_t *data, size_t data_length,
+ const uint8_t *key, size_t key_length,
+ psa_status_t result);
+
+void rpmb_platform_mock_expect_get_nonce(void *context, const uint8_t *nonce, size_t nonce_length,
+ psa_status_t result);
+
+void rpmb_platform_mock_expect_calculate_mac(void *context, const uint8_t *key, size_t key_length,
+ const struct rpmb_data_frame *frames,
+ size_t frame_count, const uint8_t *mac,
+ size_t mac_length, psa_status_t result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_PLATFORM_MOCK_H_ */
diff --git a/components/service/rpmb/frontend/platform/mock/test/component.cmake b/components/service/rpmb/frontend/platform/mock/test/component.cmake
new file mode 100644
index 000000000..e74c9fe84
--- /dev/null
+++ b/components/service/rpmb/frontend/platform/mock/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/test_rpmb_platform_mock.cpp"
+ )
diff --git a/components/service/rpmb/frontend/platform/mock/test/test_rpmb_platform_mock.cpp b/components/service/rpmb/frontend/platform/mock/test/test_rpmb_platform_mock.cpp
new file mode 100644
index 000000000..2498e9aaa
--- /dev/null
+++ b/components/service/rpmb/frontend/platform/mock/test/test_rpmb_platform_mock.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+#include "../rpmb_platform_mock.h"
+#include <string.h>
+
+TEST_GROUP(rpmb_platform_mock) {
+ TEST_SETUP()
+ {
+ platform = rpmb_platform_mock_init(&platform_mock);
+ }
+
+ TEST_TEARDOWN()
+ {
+ rpmb_platform_mock_deinit(&platform_mock);
+
+ mock().checkExpectations();
+ mock().clear();
+ }
+
+ struct rpmb_platform *platform;
+ struct rpmb_platform_mock platform_mock;
+ const uint32_t dev_id = 1;
+};
+
+TEST(rpmb_platform_mock, derive_key)
+{
+ const uint8_t data[4] = { 1, 2, 3, 4};
+ const uint8_t expected_key[4] = { 5, 6, 7, 8};
+ uint8_t key[4] = { 0 };
+
+ rpmb_platform_mock_expect_derive_key(platform, data, sizeof(data), expected_key,
+ sizeof(expected_key), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_SUCCESS, platform->interface->derive_key(platform, data, sizeof(data),
+ key, sizeof(key)));
+ MEMCMP_EQUAL(expected_key, key, sizeof(expected_key));
+}
+
+TEST(rpmb_platform_mock, get_nonce)
+{
+ const uint8_t expected_nonce[4] = { 5, 6, 7, 8};
+ uint8_t nonce[4] = { 0 };
+
+ rpmb_platform_mock_expect_get_nonce(platform, expected_nonce, sizeof(expected_nonce),
+ PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_SUCCESS, platform->interface->get_nonce(platform, nonce, sizeof(nonce)));
+ MEMCMP_EQUAL(expected_nonce, nonce, sizeof(expected_nonce));
+}
+
+TEST(rpmb_platform_mock, calculate_mac)
+{
+ const uint8_t key[4] = { 1, 2, 3, 4 };
+ struct rpmb_data_frame frames[3] = { 0 };
+ const uint8_t expected_mac[4] = { 5, 6, 7, 8 };
+ uint8_t mac[4] = { 0 };
+
+ memset(frames, 0x5a, sizeof(frames));
+
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), frames, 3, expected_mac,
+ sizeof(expected_mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_SUCCESS, platform->interface->calculate_mac(platform, key, sizeof(key),
+ frames, 3, mac, sizeof(mac)));
+ MEMCMP_EQUAL(expected_mac, mac, sizeof(expected_mac));
+} \ No newline at end of file
diff --git a/components/service/rpmb/frontend/rpmb_frontend.c b/components/service/rpmb/frontend/rpmb_frontend.c
new file mode 100644
index 000000000..9c212962c
--- /dev/null
+++ b/components/service/rpmb/frontend/rpmb_frontend.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpmb_frontend.h"
+#include "util.h"
+#include <stdlib.h>
+#include <string.h>
+
+static void u32_to_rpmb_field(uint32_t u32, uint8_t *rpmb_field)
+{
+ rpmb_field[0] = (u32 >> 24) & 0xff;
+ rpmb_field[1] = (u32 >> 16) & 0xff;
+ rpmb_field[2] = (u32 >> 8) & 0xff;
+ rpmb_field[3] = u32 & 0xff;
+}
+
+static uint32_t u32_from_rpmb_field(const uint8_t *rpmb_field)
+{
+ return (rpmb_field[0] << 24) | (rpmb_field[1] << 16) | (rpmb_field[2] << 8) | rpmb_field[3];
+}
+
+static void u16_to_rpmb_field(uint16_t u16, uint8_t *rpmb_field)
+{
+ rpmb_field[0] = (u16 >> 8) & 0xff;
+ rpmb_field[1] = u16 & 0xff;
+}
+
+static uint16_t u16_from_rpmb_field(const uint8_t *rpmb_field)
+{
+ return (rpmb_field[0] << 8) | rpmb_field[1];
+}
+
+static inline psa_status_t rpmb_derive_key(struct rpmb_frontend *frontend, const uint8_t *data,
+ size_t data_length, uint8_t *key, size_t key_length)
+{
+ struct rpmb_platform *platform = frontend->platform;
+
+ return platform->interface->derive_key(platform->context, data, data_length, key,
+ key_length);
+}
+
+
+static inline psa_status_t rpmb_get_nonce(struct rpmb_frontend *frontend, uint8_t *nonce,
+ size_t nonce_length)
+{
+ struct rpmb_platform *platform = frontend->platform;
+
+ return platform->interface->get_nonce(platform->context, nonce, nonce_length);
+}
+
+
+static inline psa_status_t rpmb_calculate_mac(struct rpmb_frontend *frontend,
+ const struct rpmb_data_frame *frames,
+ size_t frame_count, uint8_t *mac)
+{
+ struct rpmb_platform *platform = frontend->platform;
+
+ return platform->interface->calculate_mac(platform->context, frontend->key,
+ sizeof(frontend->key), frames, frame_count, mac,
+ RPMB_KEY_MAC_SIZE);
+}
+
+static psa_status_t rpmb_read_write_counter(struct rpmb_frontend *context)
+{
+ struct rpmb_data_frame frame = { 0 };
+ size_t response_frame_count = 1;
+ uint8_t nonce[RPMB_NONCE_SIZE] = { 0 };
+ uint8_t mac[RPMB_KEY_MAC_SIZE] = { 0 };
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ uint16_t resp_type = 0;
+ uint16_t op_result = RPMB_RES_GENERAL_FAILURE;
+
+ status = rpmb_get_nonce(context, nonce, sizeof(nonce));
+ if (status != PSA_SUCCESS)
+ return status;
+
+ /* Setting nonce and request type */
+ memcpy(frame.nonce, nonce, sizeof(frame.nonce));
+ u16_to_rpmb_field(RPMB_REQ_TYPE_READ_WRITE_COUNTER, frame.msg_type);
+
+ status = rpmb_backend_data_request(context->backend, context->dev_id, &frame, 1,
+ &frame, &response_frame_count);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ /* Validate response type, result, nonce and MAC */
+ op_result = u16_from_rpmb_field(frame.op_result);
+ if (op_result != RPMB_RES_OK)
+ return PSA_ERROR_STORAGE_FAILURE;
+
+ resp_type = u16_from_rpmb_field(frame.msg_type);
+ if (resp_type != RPMB_RESP_TYPE_READ_WRITE_COUNTER)
+ return PSA_ERROR_STORAGE_FAILURE;
+
+ if (memcmp(frame.nonce, nonce, sizeof(frame.nonce)) != 0)
+ return PSA_ERROR_STORAGE_FAILURE;
+
+ status = rpmb_calculate_mac(context, &frame, 1, mac);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ if (memcmp(frame.key_mac, mac, sizeof(frame.key_mac)) != 0)
+ return PSA_ERROR_STORAGE_FAILURE;
+
+ context->write_counter = u32_from_rpmb_field(frame.write_counter);
+
+ return PSA_SUCCESS;
+}
+
+#if RPMB_WRITE_KEY
+static bool rpmb_is_key_set(struct rpmb_frontend *context)
+{
+ return rpmb_read_write_counter(context) == PSA_SUCCESS;
+}
+
+static psa_status_t rpmb_write_key(struct rpmb_frontend *context)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame frames[2] = { 0 };
+ size_t response_count = 0;
+ uint16_t msg_type = 0;
+
+ /* Authentication Key Data Packet */
+ memcpy(frames[0].key_mac, context->key, sizeof(frames[0].key_mac));
+ u16_to_rpmb_field(RPMB_REQ_TYPE_AUTHENTICATION_KEY_WRITE, frames[0].msg_type);
+
+ /* Result Register Read Request Packet*/
+ u16_to_rpmb_field(RPMB_REQ_TYPE_RESULT_READ_REQUEST, frames[1].msg_type);
+
+ response_count = 1;
+ status = rpmb_backend_data_request(context->backend, context->dev_id, frames, 2, frames,
+ &response_count);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ if (response_count != 1)
+ return PSA_ERROR_INSUFFICIENT_DATA;
+
+ /* Parse Response for Key Programming Result Request */
+ msg_type = u16_from_rpmb_field(frames[0].msg_type);
+ if (u16_from_rpmb_field(frames[0].op_result) != RPMB_RES_OK ||
+ msg_type != RPMB_RESP_TYPE_AUTHENTICATION_KEY_WRITE)
+ return PSA_ERROR_STORAGE_FAILURE;
+
+ return PSA_SUCCESS;
+}
+#endif /* RPMB_WRITE_KEY */
+
+psa_status_t rpmb_frontend_create(struct rpmb_frontend *context, struct rpmb_platform *platform,
+ struct rpmb_backend *backend, uint32_t dev_id)
+{
+ if (!context || !platform || !backend)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ *context = (struct rpmb_frontend){ 0 };
+
+ context->platform = platform;
+ context->backend = backend;
+ context->dev_id = dev_id;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rpmb_frontend_init(struct rpmb_frontend *context)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_dev_info dev_info = { 0 };
+
+ status = rpmb_backend_get_dev_info(context->backend, context->dev_id, &dev_info);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ if (!dev_info.rpmb_size_mult)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (MUL_OVERFLOW(dev_info.rpmb_size_mult, RPMB_SIZE_MULT_UNIT / RPMB_DATA_SIZE,
+ &context->block_count))
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ /* Mask product revision and CRC because it might change on eMMC FFU */
+ dev_info.cid[RPMB_CID_PRODUCT_REVISION] = 0;
+ dev_info.cid[RPMB_CID_CRC7] = 0;
+ status = rpmb_derive_key(context, dev_info.cid, sizeof(dev_info.cid), context->key,
+ RPMB_KEY_MAC_SIZE);
+ if (status != PSA_SUCCESS)
+ return status;
+
+#if RPMB_WRITE_KEY
+ if (!rpmb_is_key_set(context)) {
+ status = rpmb_write_key(context);
+ if (status != PSA_SUCCESS)
+ return status;
+ }
+#endif /* RPMB_WRITE_KEY */
+
+ status = rpmb_read_write_counter(context);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ context->initialized = true;
+
+ return PSA_SUCCESS;
+}
+
+void rpmb_frontend_destroy(struct rpmb_frontend *context)
+{
+ *context = (struct rpmb_frontend){ 0 };
+}
+
+psa_status_t rpmb_frontend_block_size(struct rpmb_frontend *context, size_t *block_size)
+{
+ *block_size = RPMB_DATA_SIZE;
+ return PSA_SUCCESS;
+}
+
+psa_status_t rpmb_frontend_block_count(struct rpmb_frontend *context, size_t *block_count)
+{
+ if (!context->initialized)
+ return PSA_ERROR_BAD_STATE;
+
+ *block_count = context->block_count;
+ return PSA_SUCCESS;
+}
+
+psa_status_t rpmb_frontend_write(struct rpmb_frontend *context, uint16_t block_index,
+ const uint8_t *data, size_t block_count)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame frames[2] = { 0 };
+ uint8_t mac[RPMB_KEY_MAC_SIZE] = { 0 };
+ size_t response_count = 0;
+ uint32_t write_counter = 0;
+ uint16_t op_result = 0;
+ size_t last_block = 0;
+ uint16_t msg_type = 0;
+ uint16_t address = 0;
+ uint16_t i = 0;
+
+ if (!context)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (!context->initialized)
+ return PSA_ERROR_BAD_STATE;
+
+ /* Validating block range */
+ if (block_index >= context->block_count ||
+ ADD_OVERFLOW(block_index, block_count, &last_block) ||
+ last_block > context->block_count)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (block_count == 0)
+ return PSA_SUCCESS;
+
+ for (i = 0; i < block_count; i++) {
+ /* Program Data Packet */
+ memset(frames, 0x00, sizeof(frames));
+ memcpy(frames[0].data, &data[i * RPMB_DATA_SIZE], RPMB_DATA_SIZE);
+ u32_to_rpmb_field(context->write_counter, frames[0].write_counter);
+ u16_to_rpmb_field(block_index + i, frames[0].address);
+ u16_to_rpmb_field(1, frames[0].block_count);
+ u16_to_rpmb_field(RPMB_REQ_TYPE_AUTHENTICATED_DATA_WRITE, frames[0].msg_type);
+
+ status = rpmb_calculate_mac(context, frames, 1, frames[0].key_mac);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ /* Result Register Read Request Packet */
+ memset(&frames[1], 0x00, sizeof(frames[1]));
+ u16_to_rpmb_field(RPMB_REQ_TYPE_RESULT_READ_REQUEST, frames[1].msg_type);
+
+ /* Do the request to the backend */
+ response_count = 1;
+ status = rpmb_backend_data_request(context->backend, context->dev_id, frames,
+ ARRAY_SIZE(frames), frames, &response_count);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ if (response_count != 1)
+ return PSA_ERROR_INSUFFICIENT_DATA;
+
+ /* Parse Response for Data Programming Result Request */
+ status = rpmb_calculate_mac(context, &frames[0], 1, mac);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ if (memcmp(frames[0].key_mac, mac, sizeof(mac)) != 0)
+ return PSA_ERROR_INVALID_SIGNATURE;
+
+ write_counter = u32_from_rpmb_field(frames[0].write_counter);
+ if (write_counter != context->write_counter + 1)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ address = u16_from_rpmb_field(frames[0].address);
+ if (address != block_index + i)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ op_result = u16_from_rpmb_field(frames[0].op_result);
+ if (op_result != RPMB_RES_OK)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ msg_type = u16_from_rpmb_field(frames[0].msg_type);
+ if (msg_type != RPMB_RESP_TYPE_AUTHENTICATED_DATA_WRITE)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ context->write_counter = write_counter;
+ }
+
+ return PSA_SUCCESS;
+
+}
+
+psa_status_t rpmb_frontend_read(struct rpmb_frontend *context, uint16_t block_index,
+ uint8_t *data, size_t block_count)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ uint8_t mac[RPMB_KEY_MAC_SIZE] = { 0 };
+ uint8_t nonce[RPMB_NONCE_SIZE] = { 0 };
+ struct rpmb_data_frame *frames = NULL;
+ size_t response_count = 0;
+ size_t last_block = 0;
+ uint16_t msg_type = 0;
+ uint16_t i = 0;
+
+ if (!context)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (!context->initialized)
+ return PSA_ERROR_BAD_STATE;
+
+ /* Validating block range */
+ if (block_index >= context->block_count ||
+ ADD_OVERFLOW(block_index, block_count, &last_block) ||
+ last_block > context->block_count)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ if (block_count == 0)
+ return PSA_SUCCESS;
+
+ frames = (struct rpmb_data_frame *)calloc(block_count, sizeof(*frames));
+ if (!frames)
+ return PSA_ERROR_INSUFFICIENT_MEMORY;
+
+ /* Data Read Request Initiation Packet */
+ status = rpmb_get_nonce(context, nonce, sizeof(nonce));
+ if (status != PSA_SUCCESS)
+ goto err;
+
+ memcpy(frames[0].nonce, nonce, sizeof(frames[0].nonce));
+ u16_to_rpmb_field(block_index, frames[0].address);
+ u16_to_rpmb_field(block_count, frames[0].block_count);
+ u16_to_rpmb_field(RPMB_REQ_TYPE_AUTHENTICATED_DATA_READ, frames[0].msg_type);
+
+ response_count = block_count;
+ status = rpmb_backend_data_request(context->backend, context->dev_id, frames, 1, frames,
+ &response_count);
+ if (status != PSA_SUCCESS)
+ goto err;
+
+ if (response_count != block_count) {
+ status = PSA_ERROR_INSUFFICIENT_DATA;
+ goto err;
+ }
+
+ status = rpmb_calculate_mac(context, frames, block_count, mac);
+ if (status != PSA_SUCCESS)
+ goto err;
+
+ if (memcmp(mac, frames[block_count - 1].key_mac, sizeof(mac)) != 0) {
+ status = PSA_ERROR_INVALID_SIGNATURE;
+ goto err;
+ }
+
+ for (i = 0; i < block_count; i++) {
+ /* Parse Read Data Packets */
+ if (memcmp(frames[i].nonce, nonce, sizeof(nonce)) != 0) {
+ status = PSA_ERROR_INVALID_SIGNATURE;
+ goto err;
+ }
+
+ msg_type = u16_from_rpmb_field(frames[i].msg_type);
+ if (u16_from_rpmb_field(frames[i].address) != block_index ||
+ u16_from_rpmb_field(frames[i].block_count) != block_count ||
+ u16_from_rpmb_field(frames[i].op_result) != RPMB_RES_OK ||
+ msg_type != RPMB_RESP_TYPE_AUTHENTICATED_DATA_READ) {
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ goto err;
+ }
+
+ memcpy(&data[i * RPMB_DATA_SIZE], frames[i].data, RPMB_DATA_SIZE);
+ }
+
+err:
+ free(frames);
+ return status;
+}
diff --git a/components/service/rpmb/frontend/rpmb_frontend.h b/components/service/rpmb/frontend/rpmb_frontend.h
new file mode 100644
index 000000000..e4eb8cee8
--- /dev/null
+++ b/components/service/rpmb/frontend/rpmb_frontend.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_FRONTEND_H_
+#define RPMB_FRONTEND_H_
+
+#include "components/service/rpmb/backend/rpmb_backend.h"
+#include "components/rpc/common/caller/rpc_caller_session.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief RPMB platform interface
+ *
+ * It the interface for the necessary platform dependent functions:
+ * * deriving RPMB key from hardware unique key
+ * * get random nonce value
+ * * calculate RPMB MAC value
+ */
+struct rpmb_platform_interface {
+ /**
+ * \brief Device key from hardware unique key for creating the RPMB authentication key
+ *
+ * \param context[in] Platform context
+ * \param data[in] Key derivation data (i.e. salt)
+ * \param data_length[in] Key derivation data length
+ * \param key[out] Derived authentication key
+ * \param key_length[in] Required authentication key length
+ * \return psa_status_t
+ */
+ psa_status_t (*derive_key)(void *context, const uint8_t *data, size_t data_length,
+ uint8_t *key, size_t key_length);
+
+ /**
+ * \brief Get random nonce value
+ *
+ * \param context[in] Platform context
+ * \param nonce[out] Generated nonce value
+ * \param nonce_length[in] Nonce length
+ * \return psa_status_t
+ */
+ psa_status_t (*get_nonce)(void *context, uint8_t *nonce, size_t nonce_length);
+
+ /**
+ * \brief Calculate MAC field value
+ *
+ * \param context[in] Platform context
+ * \param key[in] Authentication key
+ * \param key_length[in] Authentication key length
+ * \param frames[in] Data frames
+ * \param frame_count[in] Data frame count
+ * \param mac[out] Calculated MAC value
+ * \param mac_length[in] MAC value length
+ * \return psa_status_t
+ */
+ psa_status_t (*calculate_mac)(void *context, const uint8_t *key, size_t key_length,
+ const struct rpmb_data_frame *frames, size_t frame_count,
+ uint8_t *mac, size_t mac_length);
+};
+
+/**
+ * \brief RPMB platform
+ *
+ * Generic object for storing the RPMB platform interface and the implementation specific context.
+ */
+struct rpmb_platform {
+ void *context;
+ struct rpmb_platform_interface *interface;
+};
+
+/**
+ * \brief RPMB frontend
+ *
+ * The RPMB frontend provides a high level read/write interface for accessing
+ * the RPMB device and it does calls to the RPMB backend. This component
+ * contains the main RPMB logic, including:
+ * * Writing authentication key
+ * * Handling the write counter
+ * * Building and verifying RPMB data frames
+ */
+struct rpmb_frontend {
+ struct rpmb_platform *platform;
+ struct rpmb_backend *backend;
+ uint32_t dev_id;
+ bool initialized;
+ size_t block_count;
+ uint8_t key[RPMB_KEY_MAC_SIZE];
+ uint32_t write_counter;
+};
+
+/**
+ * \brief Create RPMB frontend
+ *
+ * This function only initializes the internal objects. It doesn't require the backend to be able
+ * to access the RPMB hardware.
+ *
+ * \param context[in] RPMB frontend context
+ * \param platform[in] RPMB platform
+ * \param backend[in] RPMB backend
+ * \param dev_id[in] Device ID
+ * \return psa_status_t
+ */
+psa_status_t rpmb_frontend_create(struct rpmb_frontend *context, struct rpmb_platform *platform,
+ struct rpmb_backend *backend, uint32_t dev_id);
+
+/**
+ * \brief Init RPMB frontend
+ *
+ * This function requires access to the RPMB hardware via the backend. It reads derives the
+ * authentication key, reads the write counter and possibly writes the authentication key.
+ *
+ * \param context[in] RPMB frontend context
+ * \return psa_status_t
+ */
+psa_status_t rpmb_frontend_init(struct rpmb_frontend *context);
+
+/**
+ * \brief Destroy RPMB frontend
+ *
+ * \param context[in] RPMB frontend context
+ */
+void rpmb_frontend_destroy(struct rpmb_frontend *context);
+
+/**
+ * \brief Query RPMB block size
+ *
+ * \param context[in] RPMB frontend context
+ * \param block_size[out] Block size in bytes
+ * \return psa_status_t
+ */
+psa_status_t rpmb_frontend_block_size(struct rpmb_frontend *context, size_t *block_size);
+
+/**
+ * \brief Query RPMB block count
+ *
+ * \param context[in] RPMB frontend context
+ * \param block_count[out] Block count
+ * \return psa_status_t
+ */
+psa_status_t rpmb_frontend_block_count(struct rpmb_frontend *context, size_t *block_count);
+
+/**
+ * \brief Write complete blocks to RPMB
+ *
+ * \param context[in] RPMB frontend context
+ * \param block_index[in] Block index
+ * \param data[in] Data, its size must be [block count] * [block size]
+ * \param block_count[in] Block count
+ * \return psa_status_t
+ */
+psa_status_t rpmb_frontend_write(struct rpmb_frontend *context, uint16_t block_index,
+ const uint8_t *data, size_t block_count);
+
+/**
+ * \brief Read complete blocks from RPMB
+ *
+ * \param context[in] RPMB frontend context
+ * \param block_index[in] Block index
+ * \param data[out] Data, its size must be [block count] * [block size]
+ * \param block_count[in] Block count
+ * \return psa_status_t
+ */
+psa_status_t rpmb_frontend_read(struct rpmb_frontend *context, uint16_t block_index,
+ uint8_t *data, size_t block_count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_CLIENT_H_ */
diff --git a/components/service/rpmb/frontend/test/component.cmake b/components/service/rpmb/frontend/test/component.cmake
new file mode 100644
index 000000000..2ad0e8b37
--- /dev/null
+++ b/components/service/rpmb/frontend/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/test_rpmb_frontend.cpp"
+)
diff --git a/components/service/rpmb/frontend/test/test_rpmb_frontend.cpp b/components/service/rpmb/frontend/test/test_rpmb_frontend.cpp
new file mode 100644
index 000000000..714c956c0
--- /dev/null
+++ b/components/service/rpmb/frontend/test/test_rpmb_frontend.cpp
@@ -0,0 +1,1065 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+#include "../rpmb_frontend.h"
+#include "../platform/mock/rpmb_platform_mock.h"
+#include "../../backend/mock/rpmb_backend_mock.h"
+#include <string.h>
+
+TEST_GROUP(rpmb_frontend) {
+ TEST_SETUP()
+ {
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+ platform = rpmb_platform_mock_init(&platform_mock);
+ CHECK(platform != NULL);
+ backend = rpmb_backend_mock_init(&backend_mock);
+ CHECK(backend != NULL);
+ status = rpmb_frontend_create(&frontend, platform, backend, dev_id);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ TEST_TEARDOWN()
+ {
+ rpmb_frontend_destroy(&frontend);
+ rpmb_backend_mock_deinit(&backend_mock);
+ rpmb_platform_mock_deinit(&platform_mock);
+
+ mock().checkExpectations();
+ mock().clear();
+ }
+
+ void init_data_frame(struct rpmb_data_frame *frame, uint16_t address, uint16_t block_count,
+ uint16_t msg_type, const uint8_t *data, const uint8_t *nonce)
+ {
+ frame->address[0] = (address >> 8) & 0xff;
+ frame->address[1] = address & 0xff;
+ frame->block_count[0] = (block_count >> 8) & 0xff;
+ frame->block_count[1] = block_count & 0xff;
+ frame->msg_type[0] = (msg_type >> 8) & 0xff;
+ frame->msg_type[1] = msg_type & 0xff;
+
+ if (data)
+ memcpy(frame->data, data, sizeof(frame->data));
+
+ if (nonce)
+ memcpy(frame->nonce, nonce, sizeof(frame->nonce));
+ }
+
+ void init()
+ {
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+
+ size_t response_count = 1;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid),
+ key, sizeof(key), PSA_SUCCESS);
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+
+ memcpy(request.nonce, nonce, sizeof(request.nonce));
+ request.msg_type[0] = 0x00;
+ request.msg_type[1] = 0x02;
+ memcpy(response.nonce, nonce, sizeof(response.nonce));
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ response.msg_type[0] = 0x02;
+ response.msg_type[1] = 0x00;
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ struct rpmb_frontend frontend;
+ struct rpmb_platform *platform;
+ struct rpmb_platform_mock platform_mock;
+ struct rpmb_backend *backend;
+ struct rpmb_backend_mock backend_mock;
+ const uint32_t dev_id = 1;
+ const struct rpmb_dev_info dev_info = {
+ .cid = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x00},
+ .rpmb_size_mult = 16
+ };
+ const uint8_t key[RPMB_KEY_MAC_SIZE] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0 };
+
+ const uint8_t nonce[RPMB_NONCE_SIZE] = {
+ 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22,
+ 0x11, 0x00, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa
+ };
+ const uint8_t mac[RPMB_KEY_MAC_SIZE] = {
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70 };
+};
+
+TEST(rpmb_frontend, create_null)
+{
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_create(NULL, platform, backend, 0));
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_create(&frontend, NULL, backend, 0));
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_create(&frontend, platform, NULL, 0));
+}
+
+TEST(rpmb_frontend, init_get_dev_info_fail)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_dev_info dev_info = { 0 };
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info,
+ PSA_ERROR_COMMUNICATION_FAILURE);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_COMMUNICATION_FAILURE, status);
+}
+
+TEST(rpmb_frontend, init_zero_mult)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_dev_info dev_info = { 0 }; /* size_mult is zero */
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
+}
+
+TEST(rpmb_frontend, init_derive_key_fail)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid), key,
+ sizeof(key), PSA_ERROR_BAD_STATE);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, status);
+}
+
+TEST(rpmb_frontend, init_get_nonce_fail)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid), key,
+ sizeof(key), PSA_SUCCESS);
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_ERROR_BAD_STATE);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, status);
+}
+
+TEST(rpmb_frontend, init_read_write_counter_fail)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame request = { 0 };
+
+ size_t response_count = 1;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid), key,
+ sizeof(key), PSA_SUCCESS);
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+
+ memcpy(request.nonce, nonce, sizeof(request.nonce));
+ request.msg_type[0] = 0x00;
+ request.msg_type[1] = 0x02;
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &request, 1,
+ &response_count, PSA_ERROR_BAD_STATE);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, status);
+}
+
+TEST(rpmb_frontend, init_read_write_counter_invalid_result)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+
+ size_t response_count = 1;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid), key,
+ sizeof(key), PSA_SUCCESS);
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+
+ memcpy(request.nonce, nonce, sizeof(request.nonce));
+ request.msg_type[0] = 0x00;
+ request.msg_type[1] = 0x02;
+ response.op_result[0] = 0xff;
+ response.op_result[1] = 0xff;
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_count, PSA_SUCCESS);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, status);
+}
+
+TEST(rpmb_frontend, init_read_write_counter_invalid_type)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+
+ size_t response_count = 1;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid), key,
+ sizeof(key), PSA_SUCCESS);
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+
+ memcpy(request.nonce, nonce, sizeof(request.nonce));
+ request.msg_type[0] = 0x00;
+ request.msg_type[1] = 0x02;
+ response.msg_type[0] = 0xff;
+ response.msg_type[1] = 0xff;
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_count, PSA_SUCCESS);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, status);
+}
+
+TEST(rpmb_frontend, init_read_write_counter_invalid_nonce)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+
+ size_t response_count = 1;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid), key,
+ sizeof(key), PSA_SUCCESS);
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+
+ memcpy(request.nonce, nonce, sizeof(request.nonce));
+ request.msg_type[0] = 0x00;
+ request.msg_type[1] = 0x02;
+ response.msg_type[0] = 0x02;
+ response.msg_type[1] = 0x00;
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_count, PSA_SUCCESS);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, status);
+}
+
+TEST(rpmb_frontend, init_read_write_counter_calculate_mac_fail)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+
+ size_t response_count = 1;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid), key,
+ sizeof(key), PSA_SUCCESS);
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+
+ memcpy(request.nonce, nonce, sizeof(request.nonce));
+ request.msg_type[0] = 0x00;
+ request.msg_type[1] = 0x02;
+ memcpy(response.nonce, nonce, sizeof(response.nonce));
+ response.msg_type[0] = 0x02;
+ response.msg_type[1] = 0x00;
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_ERROR_BAD_STATE);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, status);
+}
+
+TEST(rpmb_frontend, init_read_write_counter_invalid_mac)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+
+ size_t response_count = 1;
+
+ rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &dev_info, PSA_SUCCESS);
+ rpmb_platform_mock_expect_derive_key(platform, dev_info.cid, sizeof(dev_info.cid), key,
+ sizeof(key), PSA_SUCCESS);
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+
+ memcpy(request.nonce, nonce, sizeof(request.nonce));
+ request.msg_type[0] = 0x00;
+ request.msg_type[1] = 0x02;
+ memcpy(response.nonce, nonce, sizeof(response.nonce));
+ response.msg_type[0] = 0x02;
+ response.msg_type[1] = 0x00;
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ status = rpmb_frontend_init(&frontend);
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, status);
+}
+
+TEST(rpmb_frontend, init_success)
+{
+ init();
+}
+
+TEST(rpmb_frontend, block_size)
+{
+ size_t block_size = 0;
+
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_block_size(&frontend, &block_size));
+ UNSIGNED_LONGS_EQUAL(256, block_size);
+}
+
+TEST(rpmb_frontend, block_count)
+{
+ size_t block_count = 0;
+
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, rpmb_frontend_block_count(&frontend, &block_count));
+
+ init();
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_block_count(&frontend, &block_count));
+
+ const size_t rpmb_mult_unit = 128 * 1024; /* The RPMB size unit is 128kB */
+ const size_t rpmb_block_size = 256;
+ const size_t expected_block_count =
+ rpmb_mult_unit * dev_info.rpmb_size_mult / rpmb_block_size;
+
+ UNSIGNED_LONGS_EQUAL(expected_block_count, block_count);
+}
+
+TEST(rpmb_frontend, write_null_context)
+{
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_write(NULL, 0, NULL, 0));
+}
+
+TEST(rpmb_frontend, write_not_initialized)
+{
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, rpmb_frontend_write(&frontend, 0, NULL, 0));
+}
+
+TEST(rpmb_frontend, write_invalid_range)
+{
+ size_t block_count = 0;
+
+ init();
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_block_count(&frontend, &block_count));
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+ rpmb_frontend_write(&frontend, block_count, NULL, 1));
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+ rpmb_frontend_write(&frontend, block_count - 1, NULL, 2));
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+ rpmb_frontend_write(&frontend, 1, NULL, block_count));
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+ rpmb_frontend_write(&frontend, block_count - 1, NULL, SIZE_MAX));
+}
+
+TEST(rpmb_frontend, write_zero_size)
+{
+ init();
+
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_write(&frontend, 0, NULL, 0));
+}
+
+TEST(rpmb_frontend, write_calculate_mac_fail)
+{
+ struct rpmb_data_frame request = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+ init_data_frame(&request, 0x0001, 0x0001, 0x0003, data, NULL);
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &request, 1, mac,
+ sizeof(mac), PSA_ERROR_STORAGE_FAILURE);
+
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_data_request_fail)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 0;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_ERROR_STORAGE_FAILURE);
+
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_response_count_fail)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 0;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INSUFFICIENT_DATA, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_mac_calc_fail)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_ERROR_BAD_STATE);
+
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_mac_check_fail)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_SIGNATURE, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_invalid_write_counter)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ response.write_counter[0] = 0xff;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_invalid_address)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ response.write_counter[3] = 0x01;
+ response.address[0] = 0xff;
+ response.address[1] = 0x00;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_invalid_result)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ response.write_counter[3] = 0x01;
+ response.address[0] = 0x00;
+ response.address[1] = 0x01;
+ response.op_result[0] = 0xff;
+ response.op_result[1] = 0xff;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_invalid_msg_type)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ response.write_counter[3] = 0x01;
+ response.address[0] = 0x00;
+ response.address[1] = 0x01;
+ response.op_result[0] = 0x00;
+ response.op_result[1] = 0x00;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write)
+{
+ struct rpmb_data_frame mac_calc_request = { 0 };
+ struct rpmb_data_frame request[2] = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ memset(data, 0x5a, sizeof(data));
+
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request, &request[0], sizeof(mac_calc_request));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ init_data_frame(&response, 0x0001, 0, 0x0300, NULL, NULL);
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ response.write_counter[3] = 0x01;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request, 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, request, 2, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_write(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, write_two_blocks)
+{
+ struct rpmb_data_frame mac_calc_request[2] = { 0 };
+ struct rpmb_data_frame request[4] = { 0 };
+ struct rpmb_data_frame response[2] = { 0 };
+ uint8_t data[RPMB_DATA_SIZE * 2] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ memset(data, 0x5a, RPMB_DATA_SIZE);
+ memset(data + RPMB_DATA_SIZE, 0x1b, RPMB_DATA_SIZE);
+
+ /* Block 1 */
+ /* The write counter is zero at this point */
+ init_data_frame(&request[0], 0x0001, 0x0001, 0x0003, data, NULL);
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request[0], &request[0], sizeof(mac_calc_request[0]));
+ memcpy(request[0].key_mac, mac, sizeof(request[0].key_mac));
+
+ request[1].msg_type[0] = 0x00;
+ request[1].msg_type[1] = 0x05;
+
+ /* Block 2 */
+ init_data_frame(&request[2], 0x0002, 0x0001, 0x0003, data + RPMB_DATA_SIZE, NULL);
+ request[2].write_counter[3] = 0x01;
+ /* Save request without mac for the calculate_mac call */
+ memcpy(&mac_calc_request[1], &request[2], sizeof(mac_calc_request[1]));
+ memcpy(request[2].key_mac, mac, sizeof(request[2].key_mac));
+
+ request[3].msg_type[0] = 0x00;
+ request[3].msg_type[1] = 0x05;
+
+ /* Response 1 */
+ memcpy(response[0].key_mac, mac, sizeof(response[0].key_mac));
+ init_data_frame(&response[0], 0x0001, 0, 0x0300, NULL, NULL);
+ response[0].write_counter[3] = 0x01;
+
+ /* Response 2 */
+ memcpy(response[1].key_mac, mac, sizeof(response[1].key_mac));
+ init_data_frame(&response[1], 0x0002, 0, 0x0300, NULL, NULL);
+ response[1].write_counter[3] = 0x02;
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request[0], 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request[0], 2, &response[0], 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response[0], 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &mac_calc_request[1], 1,
+ mac, sizeof(mac), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request[2], 2, &response[1], 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response[1], 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_write(&frontend, 1, data, 2));
+}
+
+
+
+TEST(rpmb_frontend, read_null_context)
+{
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_read(NULL, 0, NULL, 0));
+}
+
+TEST(rpmb_frontend, read_not_initialized)
+{
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, rpmb_frontend_read(&frontend, 0, NULL, 0));
+}
+
+TEST(rpmb_frontend, read_invalid_range)
+{
+ size_t block_count = 0;
+
+ init();
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_block_count(&frontend, &block_count));
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+ rpmb_frontend_read(&frontend, block_count, NULL, 1));
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+ rpmb_frontend_read(&frontend, block_count - 1, NULL, 2));
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+ rpmb_frontend_read(&frontend, block_count - 1, NULL, SIZE_MAX));
+}
+
+TEST(rpmb_frontend, read_zero_size)
+{
+ init();
+
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_read(&frontend, 0, NULL, 0));
+}
+
+TEST(rpmb_frontend, read_get_nonce_fail)
+{
+ init();
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_ERROR_BAD_STATE);
+
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, rpmb_frontend_read(&frontend, 1, NULL, 1));
+}
+
+TEST(rpmb_frontend, read_data_request_fail)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 0;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_ERROR_STORAGE_FAILURE);
+
+ LONGS_EQUAL(PSA_ERROR_STORAGE_FAILURE, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read_response_count_fail)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 0;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INSUFFICIENT_DATA, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read_mac_calc_fail)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_ERROR_BAD_STATE);
+
+ LONGS_EQUAL(PSA_ERROR_BAD_STATE, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read_mac_check_fail)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_SIGNATURE, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read_nonce_check_fail)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_SIGNATURE, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read_invalid_block_address)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ memcpy(response.nonce, nonce, sizeof(response.nonce));
+ response.address[0] = 0xff;
+ response.address[1] = 0xff;
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read_invalid_block_count)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ init_data_frame(&response, 0x0001, 0xffff, 0, NULL, nonce);
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read_invalid_result)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ init_data_frame(&response, 0x0001, 0x0001, 0, NULL, nonce);
+ response.op_result[0] = 0xff;
+ response.op_result[1] = 0xff;
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read_invalid_type)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ init_data_frame(&response, 0x0001, 0x0001, 0xffff, NULL, nonce);
+ response.op_result[0] = 0x00;
+ response.op_result[1] = 0x00;
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_ERROR_INVALID_ARGUMENT, rpmb_frontend_read(&frontend, 1, data, 1));
+}
+
+TEST(rpmb_frontend, read)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response = { 0 };
+ uint8_t expected_data[RPMB_DATA_SIZE] = { 0 };
+ uint8_t data[RPMB_DATA_SIZE] = { 0 };
+ size_t response_frame_count = 1;
+
+ init();
+
+ init_data_frame(&request, 0x0001, 0x0001, 0x0004, NULL, nonce);
+
+ memset(expected_data, 0x5a, sizeof(expected_data));
+
+ memcpy(response.key_mac, mac, sizeof(response.key_mac));
+ memcpy(response.data, expected_data, sizeof(response.data));
+ init_data_frame(&response, 0x0001, 0x0001, 0x0400, NULL, nonce);
+ response.op_result[0] = 0x00;
+ response.op_result[1] = 0x00;
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, &response, 1,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), &response, 1, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_read(&frontend, 1, data, 1));
+ MEMCMP_EQUAL(expected_data, data, sizeof(expected_data));
+}
+
+TEST(rpmb_frontend, read_two_blocks)
+{
+ struct rpmb_data_frame request = { 0 };
+ struct rpmb_data_frame response[2] = { 0 };
+ uint8_t expected_data[RPMB_DATA_SIZE * 2] = { 0 };
+ uint8_t data[RPMB_DATA_SIZE * 2] = { 0 };
+ size_t response_frame_count = 2;
+
+ init();
+
+ memset(expected_data, 0x5a, RPMB_DATA_SIZE);
+ memset(expected_data + RPMB_DATA_SIZE, 0x1b, RPMB_DATA_SIZE);
+
+ init_data_frame(&request, 0x0001, 0x0002, 0x0004, NULL, nonce);
+
+ memcpy(response[0].key_mac, mac, sizeof(response[0].key_mac));
+ memcpy(response[0].data, expected_data, sizeof(response[0].data));
+ init_data_frame(&response[0], 0x0001, 0x0002, 0x0400, NULL, nonce);
+ response[0].op_result[0] = 0x00;
+ response[0].op_result[1] = 0x00;
+
+ memcpy(response[1].key_mac, mac, sizeof(response[1].key_mac));
+ memcpy(response[1].data, expected_data + RPMB_DATA_SIZE, sizeof(response[1].data));
+ init_data_frame(&response[1], 0x0001, 0x0002, 0x0400, NULL, nonce);
+ response[1].op_result[0] = 0x00;
+ response[1].op_result[1] = 0x00;
+
+ rpmb_platform_mock_expect_get_nonce(platform, nonce, sizeof(nonce), PSA_SUCCESS);
+ rpmb_backend_mock_expect_data_request(backend, dev_id, &request, 1, response, 2,
+ &response_frame_count, PSA_SUCCESS);
+ rpmb_platform_mock_expect_calculate_mac(platform, key, sizeof(key), response, 2, mac,
+ sizeof(mac), PSA_SUCCESS);
+
+ LONGS_EQUAL(PSA_SUCCESS, rpmb_frontend_read(&frontend, 1, data, 2));
+ MEMCMP_EQUAL(expected_data, data, sizeof(expected_data));
+}
+
diff --git a/components/service/rpmb/provider/component.cmake b/components/service/rpmb/provider/component.cmake
new file mode 100644
index 000000000..a61666790
--- /dev/null
+++ b/components/service/rpmb/provider/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpmb_provider.c"
+)
diff --git a/components/service/rpmb/provider/rpmb_provider.c b/components/service/rpmb/provider/rpmb_provider.c
new file mode 100644
index 000000000..847eec15a
--- /dev/null
+++ b/components/service/rpmb/provider/rpmb_provider.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpmb_provider.h"
+#include "components/service/rpmb/backend/rpmb_backend.h"
+#include "protocols/service/rpmb/packed-c/rpmb_proto.h"
+#include "util.h"
+#include <string.h>
+
+static rpc_status_t get_dev_info_handler(void *context, struct rpc_request *req)
+{
+ struct rpmb_provider *this_context = (struct rpmb_provider *)context;
+ struct rpmb_request_get_dev_info *request_desc = NULL;
+ struct rpmb_response_get_dev_info *response_desc = NULL;
+
+ if (req->request.data_length < sizeof(*request_desc))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+
+ if (req->response.size < sizeof(*response_desc))
+ return RPC_ERROR_INVALID_RESPONSE_BODY;
+
+ request_desc = (struct rpmb_request_get_dev_info *)(req->request.data);
+ response_desc = (struct rpmb_response_get_dev_info *)(req->response.data);
+
+ req->service_status = rpmb_backend_get_dev_info(this_context->backend, request_desc->dev_id,
+ &response_desc->dev_info);
+
+ if (!req->service_status)
+ req->response.data_length = sizeof(*response_desc);
+
+ return RPC_SUCCESS;
+}
+
+static bool validate_size(size_t header_size, uint32_t frame_count, size_t available_length,
+ size_t *total_size)
+{
+ /*
+ * Checking if [data frame count] * [data frame size] + [header size] fits into the RPC
+ * buffer.
+ */
+
+ if (MUL_OVERFLOW(frame_count, sizeof(struct rpmb_data_frame), total_size))
+ return false;
+
+ if (ADD_OVERFLOW(*total_size, header_size, total_size))
+ return false;
+
+ if (*total_size > available_length)
+ return false;
+
+ return true;
+}
+
+static rpc_status_t data_request_handler(void *context, struct rpc_request *req)
+{
+ struct rpmb_provider *this_context = (struct rpmb_provider *)context;
+ struct rpmb_request_data_request *request_desc = NULL;
+ struct rpmb_response_data_request *response_desc = NULL;
+ size_t response_frame_count = 0;
+ size_t total_size = 0;
+
+ if (req->request.data_length < sizeof(*request_desc))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+
+ request_desc = (struct rpmb_request_data_request *)(req->request.data);
+
+ if (!validate_size(sizeof(*request_desc), request_desc->request_frame_count,
+ req->request.data_length, &total_size))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+
+ if (!validate_size(sizeof(*response_desc), request_desc->max_response_frame_count,
+ req->response.size, &total_size))
+ return RPC_ERROR_INVALID_RESPONSE_BODY;
+
+ response_desc = (struct rpmb_response_data_request *)(req->response.data);
+ response_frame_count = request_desc->max_response_frame_count;
+
+ req->service_status = rpmb_backend_data_request(
+ this_context->backend,
+ request_desc->dev_id,
+ request_desc->request_frames,
+ request_desc->request_frame_count,
+ response_desc->response_frames,
+ &response_frame_count);
+
+ if (!req->service_status) {
+ if (!validate_size(sizeof(*response_desc), response_frame_count,
+ req->response.size, &total_size))
+ return RPC_ERROR_INVALID_RESPONSE_BODY;
+
+ response_desc->response_frame_count = response_frame_count;
+ req->response.data_length = total_size;
+ }
+
+ return RPC_SUCCESS;
+}
+
+static const struct service_handler handler_table[] = {
+ {TS_RPMB_OPCODE_GET_DEV_INFO, get_dev_info_handler},
+ {TS_RPMB_OPCODE_DATA_REQUEST, data_request_handler},
+};
+
+struct rpc_service_interface *rpmb_provider_init(struct rpmb_provider *context,
+ struct rpmb_backend *backend,
+ const struct rpc_uuid *service_uuid)
+{
+ struct rpc_service_interface *rpc_interface = NULL;
+
+ if (!context || !backend || !service_uuid)
+ return NULL;
+
+ service_provider_init(&context->base_provider, context, service_uuid, handler_table,
+ ARRAY_SIZE(handler_table));
+
+ rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+
+ context->backend = backend;
+
+ return rpc_interface;
+}
+
+void rpmb_provider_deinit(struct rpmb_provider *context)
+{
+ (void)context;
+}
diff --git a/components/service/rpmb/provider/rpmb_provider.h b/components/service/rpmb/provider/rpmb_provider.h
new file mode 100644
index 000000000..59366e4ea
--- /dev/null
+++ b/components/service/rpmb/provider/rpmb_provider.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_PROVIDER_H_
+#define RPMB_PROVIDER_H_
+
+#include "service/common/provider/service_provider.h"
+#include "service/rpmb/backend/rpmb_backend.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief RPMB service provider
+ */
+struct rpmb_provider {
+ struct service_provider base_provider;
+ struct rpmb_backend *backend;
+};
+
+/**
+ * \brief Initializes the RPMB service provider
+ *
+ * \param context[in] Provider context
+ * \param backend[in] RPMB backend
+ * \param service_uuid[in] Service UUID
+ * \return struct rpc_service_interface* RPC service interface or NULL on error
+ */
+struct rpc_service_interface *rpmb_provider_init(struct rpmb_provider *context,
+ struct rpmb_backend *backend,
+ const struct rpc_uuid *service_uuid);
+
+/**
+ * \brief Deinitializes the RPMB service provider
+ *
+ * \param context[in] Provider context
+ */
+void rpmb_provider_deinit(struct rpmb_provider *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_PROVIDER_H_ */
diff --git a/components/service/rpmb/provider/rpmb_uuid.h b/components/service/rpmb/provider/rpmb_uuid.h
new file mode 100644
index 000000000..63ea4f549
--- /dev/null
+++ b/components/service/rpmb/provider/rpmb_uuid.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_UUID_H
+#define RPMB_UUID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TS_RPMB_SERVICE_UUID \
+{ 0x19, 0xef, 0x70, 0xbf, 0x2f, 0xbc, 0x43, 0x09, 0xbd, 0xd3, 0xc2, 0x90, 0xe9, 0x93, 0xf6, 0x50 }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPMB_UUID_H */
diff --git a/components/service/secure_storage/backend/mock_store/mock_store.c b/components/service/secure_storage/backend/mock_store/mock_store.c
index f701e01cb..23c336e12 100644
--- a/components/service/secure_storage/backend/mock_store/mock_store.c
+++ b/components/service/secure_storage/backend/mock_store/mock_store.c
@@ -1,11 +1,12 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "mock_store.h"
#include <protocols/service/psa/packed-c/status.h>
+#include "util.h"
#include <stdlib.h>
#include <string.h>
@@ -21,23 +22,32 @@ static psa_status_t mock_store_set(void *context,
const void *p_data,
uint32_t create_flags)
{
+ (void)client_id;
+
psa_status_t psa_status = PSA_ERROR_INSUFFICIENT_STORAGE;
struct mock_store *this_context = (struct mock_store*)context;
/* Check length limit */
if (data_length > MOCK_STORE_ITEM_SIZE_LIMIT) return psa_status;
+ if (!uid)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
/* Replace existing or add new item */
struct mock_store_slot *slot = find_slot(this_context, uid);
- if (slot) free_slot(slot);
- else slot = find_empty_slot(this_context);
-
if (slot) {
+ if (slot->flags & PSA_STORAGE_FLAG_WRITE_ONCE)
+ return PSA_ERROR_NOT_PERMITTED;
+ free_slot(slot);
+ } else {
+ slot = find_empty_slot(this_context);
+ }
+
+ if (slot) {
slot->item = malloc(data_length);
if (slot->item) {
-
slot->uid = uid;
slot->flags = create_flags;
slot->len = slot->capacity = data_length;
@@ -58,19 +68,26 @@ static psa_status_t mock_store_get(void *context,
void *p_data,
size_t *p_data_length)
{
- psa_status_t psa_status = PSA_ERROR_DOES_NOT_EXIST;
struct mock_store *this_context = (struct mock_store*)context;
+ (void)client_id;
+
+ if (!uid)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
/* Find the item */
struct mock_store_slot *slot = find_slot(this_context, uid);
- if (slot && (slot->len <= data_size)) {
- memcpy(p_data, slot->item, slot->len);
- *p_data_length = slot->len;
- psa_status = PSA_SUCCESS;
- }
+ if (!slot)
+ return PSA_ERROR_DOES_NOT_EXIST;
- return psa_status;
+ if (slot->len < data_offset)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ *p_data_length = MIN(slot->len - data_offset, data_size);
+ memcpy(p_data, slot->item + data_offset, *p_data_length);
+
+ return PSA_SUCCESS;
}
static psa_status_t mock_store_get_info(void *context,
@@ -78,9 +95,14 @@ static psa_status_t mock_store_get_info(void *context,
uint64_t uid,
struct psa_storage_info_t *p_info)
{
+ (void)client_id;
+
psa_status_t psa_status = PSA_ERROR_DOES_NOT_EXIST;
struct mock_store *this_context = (struct mock_store*)context;
+ if (!uid)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
/* Find item to get info about */
struct mock_store_slot *slot = find_slot(this_context, uid);
@@ -103,15 +125,24 @@ static psa_status_t mock_store_remove(void *context,
uint32_t client_id,
uint64_t uid)
{
+ (void)client_id;
+
psa_status_t psa_status = PSA_ERROR_DOES_NOT_EXIST;
struct mock_store *this_context = (struct mock_store*)context;
+ if (!uid)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
/* Find and remove the item */
struct mock_store_slot *slot = find_slot(this_context, uid);
if (slot) {
- free_slot(slot);
- psa_status = PSA_SUCCESS;
+ if (!(slot->flags & PSA_STORAGE_FLAG_WRITE_ONCE)) {
+ free_slot(slot);
+ psa_status = PSA_SUCCESS;
+ } else {
+ psa_status = PSA_ERROR_NOT_PERMITTED;
+ }
}
return psa_status;
@@ -123,6 +154,8 @@ static psa_status_t mock_store_create(void *context,
size_t capacity,
uint32_t create_flags)
{
+ (void)client_id;
+
psa_status_t psa_status = PSA_ERROR_ALREADY_EXISTS;
struct mock_store *this_context = (struct mock_store*)context;
struct mock_store_slot *slot;
@@ -144,7 +177,7 @@ static psa_status_t mock_store_create(void *context,
slot->capacity = capacity;
slot->len = 0;
- memset(slot->item, slot->capacity, 0);
+ memset(slot->item, 0, slot->capacity);
psa_status = PSA_SUCCESS;
}
else {
@@ -164,6 +197,8 @@ static psa_status_t mock_store_set_extended(void *context,
size_t data_length,
const void *p_data)
{
+ (void)client_id;
+
psa_status_t psa_status = PSA_ERROR_DOES_NOT_EXIST;
struct mock_store *this_context = (struct mock_store*)context;
struct mock_store_slot *slot;
@@ -298,4 +333,4 @@ static void free_slot(struct mock_store_slot *slot)
slot->uid = (uint64_t)(-1);
slot->item = NULL;
}
-} \ No newline at end of file
+}
diff --git a/components/service/secure_storage/backend/mock_store/test/mock_store_tests.cpp b/components/service/secure_storage/backend/mock_store/test/mock_store_tests.cpp
index 54513be7f..eb577bf5a 100644
--- a/components/service/secure_storage/backend/mock_store/test/mock_store_tests.cpp
+++ b/components/service/secure_storage/backend/mock_store/test/mock_store_tests.cpp
@@ -40,9 +40,9 @@ TEST(MockStoreTests, itsStorageLimitTest)
its_api_tests::storageLimitTest(MOCK_STORE_ITEM_SIZE_LIMIT);
}
-TEST(MockStoreTests, psCreateAndSet)
+TEST(MockStoreTests, psSet)
{
- ps_api_tests::createAndSet();
+ ps_api_tests::set();
}
TEST(MockStoreTests, psCreateAndSetExtended)
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/component.cmake b/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/component.cmake
new file mode 100644
index 000000000..be0401166
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_block_store_adapter.c"
+ )
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.c b/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.c
new file mode 100644
index 000000000..e1ce30736
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include "sfs_flash_block_store_adapter.h"
+
+static inline struct sfs_flash_block_store_adapter *get_context(
+ const struct sfs_flash_info_t *info)
+{
+ return (struct sfs_flash_block_store_adapter *)info->flash_dev;
+}
+
+static void calc_sub_block_pos(
+ const struct sfs_flash_block_store_adapter *context,
+ uint32_t block_id,
+ size_t offset,
+ uint64_t *sub_block_lba,
+ size_t *sub_block_offset)
+{
+ size_t sub_block_size = context->flash_info.sector_size;
+
+ *sub_block_lba =
+ block_id * context->blocks_per_flash_block +
+ offset / sub_block_size;
+
+ *sub_block_offset = offset % sub_block_size;
+}
+
+static psa_status_t sfs_flash_init(
+ const struct sfs_flash_info_t *info)
+{
+ struct sfs_flash_block_store_adapter *context;
+
+ /* Ensure that adapter has already been initialised */
+ if (!info || (context = get_context(info), !context->block_store))
+ return PSA_ERROR_BAD_STATE;
+
+ return PSA_SUCCESS;
+}
+
+static psa_status_t sfs_flash_read(
+ const struct sfs_flash_info_t *info,
+ uint32_t block_id,
+ uint8_t *buff,
+ size_t offset,
+ size_t size)
+{
+ psa_status_t status = PSA_SUCCESS;
+ struct sfs_flash_block_store_adapter *context = get_context(info);
+ size_t total_bytes_read = 0;
+ uint64_t sub_block_lba;
+ size_t sub_block_offset;
+
+ calc_sub_block_pos(context, block_id, offset, &sub_block_lba, &sub_block_offset);
+
+ while (total_bytes_read < size) {
+
+ size_t bytes_read = 0;
+ size_t bytes_to_read = size - total_bytes_read;
+
+ if (bytes_to_read > context->flash_info.sector_size)
+ bytes_to_read = context->flash_info.sector_size;
+
+ status = block_store_read(context->block_store,
+ context->client_id,
+ context->partition_handle,
+ sub_block_lba,
+ sub_block_offset,
+ bytes_to_read,
+ &buff[total_bytes_read],
+ &bytes_read);
+
+ if (status != PSA_SUCCESS)
+ break;
+
+ total_bytes_read += bytes_read;
+ ++sub_block_lba;
+ sub_block_offset = 0;
+ }
+
+ if ((status == PSA_SUCCESS) && (total_bytes_read != size))
+ /* Requested size invalid */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+
+ return status;
+}
+
+static psa_status_t sfs_flash_write(
+ const struct sfs_flash_info_t *info,
+ uint32_t block_id,
+ const uint8_t *buff,
+ size_t offset,
+ size_t size)
+{
+ psa_status_t status = PSA_SUCCESS;
+ struct sfs_flash_block_store_adapter *context = get_context(info);
+ size_t total_bytes_written = 0;
+ uint64_t sub_block_lba;
+ size_t sub_block_offset;
+
+ calc_sub_block_pos(context, block_id, offset, &sub_block_lba, &sub_block_offset);
+
+ while (total_bytes_written < size) {
+
+ size_t bytes_written = 0;
+ size_t bytes_to_write = size - total_bytes_written;
+
+ if (bytes_to_write > context->flash_info.sector_size)
+ bytes_to_write = context->flash_info.sector_size;
+
+ status = block_store_write(context->block_store,
+ context->client_id,
+ context->partition_handle,
+ sub_block_lba,
+ sub_block_offset,
+ &buff[total_bytes_written],
+ bytes_to_write,
+ &bytes_written);
+
+ if (status != PSA_SUCCESS)
+ break;
+
+ total_bytes_written += bytes_written;
+ ++sub_block_lba;
+ sub_block_offset = 0;
+ }
+
+ if ((status == PSA_SUCCESS) && (total_bytes_written != size))
+ /* Requested size invalid */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+
+ return status;
+}
+
+static psa_status_t sfs_flash_flush(
+ const struct sfs_flash_info_t *info)
+{
+ /* Not supported by block_store */
+ (void)info;
+ return PSA_SUCCESS;
+}
+
+static psa_status_t sfs_flash_erase(
+ const struct sfs_flash_info_t *info,
+ uint32_t block_id)
+{
+ psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+ struct sfs_flash_block_store_adapter *context = get_context(info);
+ uint64_t sub_block_lba;
+ size_t sub_block_offset;
+
+ calc_sub_block_pos(context, block_id, 0, &sub_block_lba, &sub_block_offset);
+
+ status = block_store_erase(context->block_store,
+ context->client_id,
+ context->partition_handle,
+ sub_block_lba,
+ context->blocks_per_flash_block);
+
+ return status;
+}
+
+psa_status_t sfs_flash_block_store_adapter_init(
+ struct sfs_flash_block_store_adapter *context,
+ uint32_t client_id,
+ struct block_store *block_store,
+ const struct uuid_octets *partition_guid,
+ size_t min_flash_block_size,
+ size_t max_num_files,
+ const struct sfs_flash_info_t **flash_info)
+{
+ psa_status_t status = PSA_SUCCESS;
+ struct sfs_flash_info_t *info = &context->flash_info;
+ struct storage_partition_info partition_info;
+
+ *flash_info = info;
+
+ /* Associate with the underlying block_store */
+ context->block_store = block_store;
+ context->client_id = client_id;
+
+ /* Get information about the assigned storage partition */
+ status = block_store_get_partition_info(context->block_store,
+ partition_guid, &partition_info);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ /* Initialise interface used by sfs */
+ info->flash_dev = context;
+ info->init = sfs_flash_init;
+ info->read = sfs_flash_read;
+ info->write = sfs_flash_write;
+ info->flush = sfs_flash_flush;
+ info->erase = sfs_flash_erase;
+
+ /* Attributes that are fixed when using a block_store */
+ info->flash_area_addr = 0;
+ info->program_unit = sizeof(uint8_t);
+ info->erase_val = 0xff;
+
+ /* Flash block size is an integer multiple of the underlying
+ * block size that accommodates the specified minimum flash block size.
+ */
+ context->blocks_per_flash_block =
+ (min_flash_block_size + partition_info.block_size - 1) / partition_info.block_size;
+
+ /* Set partition parameters presented to SFS */
+ info->sector_size = (uint16_t)partition_info.block_size;
+ info->block_size = (uint16_t)(partition_info.block_size * context->blocks_per_flash_block);
+ info->num_blocks = (uint16_t)(partition_info.num_blocks / context->blocks_per_flash_block);
+
+ /* sfs specific configuration */
+ info->max_file_size = (uint16_t)info->block_size;
+ info->max_num_files = (uint16_t)max_num_files;
+
+ /* Open the storage partition so that it's ready to use */
+ status = block_store_open(context->block_store,
+ context->client_id,
+ partition_guid,
+ &context->partition_handle);
+
+ return status;
+}
+
+psa_status_t sfs_flash_block_store_adapter_deinit(
+ struct sfs_flash_block_store_adapter *context)
+{
+ /* Close the storage partition */
+ psa_status_t status = block_store_close(context->block_store,
+ context->client_id,
+ context->partition_handle);
+
+ return status;
+}
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.h b/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.h
new file mode 100644
index 000000000..270170eef
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/**
+ * \file sfs_flash_block_store_adapter.h
+ *
+ * \brief Adapts the sfs flash interface to block_store interface
+ *
+ * Can be used to access a storage partition exposed by a concrete
+ * block_store. An example use is to interface to a block_store that
+ * acts as a client to the block storage service.
+ */
+
+#ifndef __SFS_FLASH_BLOCK_STORE_ADAPTER_H__
+#define __SFS_FLASH_BLOCK_STORE_ADAPTER_H__
+
+#include <stdint.h>
+#include "../sfs_flash.h"
+#include "service/block_storage/block_store/block_store.h"
+#include "common/uuid/uuid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief sfs_flash_block_store_adapter structure
+ */
+struct sfs_flash_block_store_adapter
+{
+ struct sfs_flash_info_t flash_info;
+ struct block_store *block_store;
+ storage_partition_handle_t partition_handle;
+ uint32_t client_id;
+ size_t blocks_per_flash_block;
+};
+
+/**
+ * \brief Initialize the block store adapter
+ *
+ * On success, the underlying block store is opened and the flash_info
+ * structure in initialised, based on the info queried from the block
+ * store.
+ *
+ * \param[in] context This adapter context
+ * \param[in] client_id The client id for the environment
+ * \param[in] block_store The associated block store
+ * \param[in] partition_guid The storage partition to use
+ * \param[in] min_flash_block_size Minimum sfs block size
+ * \param[in] max_num_files An sfs configuration parameter
+ * \param[out] flash_info The sfs flash interface structure
+ *
+ * \return PSA_SUCCESS when successful
+ */
+psa_status_t sfs_flash_block_store_adapter_init(
+ struct sfs_flash_block_store_adapter *context,
+ uint32_t client_id,
+ struct block_store *block_store,
+ const struct uuid_octets *partition_guid,
+ size_t min_flash_block_size,
+ size_t max_num_files,
+ const struct sfs_flash_info_t **flash_info);
+
+/**
+ * \brief Deinitialize the block store adapter
+ *
+ * \param[in] context This adapter context
+ *
+* \return PSA_SUCCESS when successful
+ */
+psa_status_t sfs_flash_block_store_adapter_deinit(
+ struct sfs_flash_block_store_adapter *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SFS_FLASH_BLOCK_STORE_ADAPTER_H__ */
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/component.cmake b/components/service/secure_storage/backend/secure_flash_store/flash/component.cmake
index a2f34e73c..b85dd512a 100644
--- a/components/service/secure_storage/backend/secure_flash_store/flash/component.cmake
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,8 +9,5 @@ if (NOT DEFINED TGT)
endif()
target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_info.c"
- "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_ram.c"
"${CMAKE_CURRENT_LIST_DIR}/sfs_flash.c"
)
-
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/ram/component.cmake b/components/service/secure_storage/backend/secure_flash_store/flash/ram/component.cmake
new file mode 100644
index 000000000..385514d58
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/ram/component.cmake
@@ -0,0 +1,18 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+if(DEFINED CFG_SFS_FLASH_AREA_SIZE)
+ target_compile_definitions(${TGT} PRIVATE SFS_FLASH_AREA_SIZE=${CFG_SFS_FLASH_AREA_SIZE})
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_info.c"
+ "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_ram.c"
+ )
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_info.c b/components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_info.c
index 7dfe803e5..ced737e00 100644
--- a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_info.c
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_info.c
@@ -1,17 +1,19 @@
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include "sfs_flash.h"
+#include "../sfs_flash.h"
#include "sfs_flash_ram.h"
-#include "../sfs_utils.h"
+#include "../../sfs_utils.h"
#define SFS_FLASH_AREA_ADDR (0x0)
/* Adjust to a size that will allow all assets to fit */
+#ifndef SFS_FLASH_AREA_SIZE
#define SFS_FLASH_AREA_SIZE (0x4000)
+#endif
/* Adjust to match the size of the flash device's physical erase unit */
#define SFS_SECTOR_SIZE (0x1000)
@@ -46,7 +48,7 @@
static uint8_t sfs_block_data[FLASH_INFO_BLOCK_SIZE * FLASH_INFO_NUM_BLOCKS];
#define FLASH_INFO_DEV sfs_block_data
-const struct sfs_flash_info_t sfs_flash_info_internal = {
+static const struct sfs_flash_info_t sfs_flash_info_ram = {
.init = sfs_flash_ram_init,
.read = sfs_flash_ram_read,
.write = sfs_flash_ram_write,
@@ -63,5 +65,10 @@ const struct sfs_flash_info_t sfs_flash_info_internal = {
.erase_val = FLASH_INFO_ERASE_VAL,
};
+const struct sfs_flash_info_t *sfs_flash_ram_instance(void)
+{
+ return &sfs_flash_info_ram;
+}
+
/* Checks at compile time that the flash device configuration is valid */
-#include "../flash_fs/sfs_flash_fs_check_info.h"
+#include "../../flash_fs/sfs_flash_fs_check_info.h"
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_ram.c b/components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.c
index e4af6e610..c3c17e4a4 100644
--- a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_ram.c
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_ram.h b/components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.h
index eecc5e57e..d70cb1b59 100644
--- a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash_ram.h
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.h
@@ -1,10 +1,13 @@
/*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
+#ifndef __SFS_FLASH_RAM_H__
+#define __SFS_FLASH_RAM_H__
+
/**
* \file sfs_flash_ram.h
*
@@ -12,7 +15,19 @@
* device using RAM. See sfs_flash.h for full documentation of functions.
*/
-#include "sfs_flash.h"
+#include "../sfs_flash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Get the sfs_flash_ram sfs_flash_info_t instance
+ *
+ * The sfs_ram_flash component has been implemented as a singleton. This
+ * returns a pointer to the singleton sfs_flash_info_t structure.
+ */
+const struct sfs_flash_info_t *sfs_flash_ram_instance(void);
/**
* \brief Initialize the Flash Interface.
@@ -43,3 +58,9 @@ psa_status_t sfs_flash_ram_flush(const struct sfs_flash_info_t *info);
*/
psa_status_t sfs_flash_ram_erase(const struct sfs_flash_info_t *info,
uint32_t block_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SFS_FLASH_RAM_H__ */
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.c b/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.c
index fce796831..89990fbe1 100644
--- a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.c
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
* Copyright (c) 2020 Cypress Semiconductor Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -12,13 +12,6 @@
#define SFS_MAX_BLOCK_DATA_COPY 256
#endif
-extern const struct sfs_flash_info_t sfs_flash_info_internal;
-
-const struct sfs_flash_info_t *sfs_flash_get_info(void)
-{
- return &sfs_flash_info_internal;
-}
-
psa_status_t sfs_flash_block_to_block_move(const struct sfs_flash_info_t *info,
uint32_t dst_block,
size_t dst_offset,
diff --git a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.h b/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.h
index 18361f206..f995fee7c 100644
--- a/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.h
+++ b/components/service/secure_storage/backend/secure_flash_store/flash/sfs_flash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -142,13 +142,6 @@ struct sfs_flash_info_t {
};
/**
- * \brief Gets the flash info structure for the provided flash device.
- *
- * \return Pointer to the flash info struct.
- */
-const struct sfs_flash_info_t *sfs_flash_get_info(void);
-
-/**
* \brief Moves data from source block ID to destination block ID.
*
* \param[in] info Flash device information
diff --git a/components/service/secure_storage/backend/secure_flash_store/secure_flash_store.c b/components/service/secure_storage/backend/secure_flash_store/secure_flash_store.c
index 5e7dea510..6508b0c3a 100644
--- a/components/service/secure_storage/backend/secure_flash_store/secure_flash_store.c
+++ b/components/service/secure_storage/backend/secure_flash_store/secure_flash_store.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -58,6 +58,8 @@ static psa_status_t sfs_set(void *context,
const void *p_data,
uint32_t create_flags)
{
+ (void)context;
+
psa_status_t status;
size_t write_size;
size_t offset;
@@ -151,11 +153,11 @@ static psa_status_t sfs_get(void *context,
void *p_data,
size_t *p_data_length)
{
+ (void)context;
+
psa_status_t status;
size_t read_size;
- uint8_t *data = p_data;
-
- data = (uint8_t *)p_data;
+ uint8_t *data = (uint8_t *)p_data;
/* Check that the UID is valid */
if (uid == SFS_INVALID_UID) {
@@ -212,6 +214,8 @@ static psa_status_t sfs_get(void *context,
static psa_status_t sfs_get_info(void *context, uint32_t client_id, uint64_t uid,
struct psa_storage_info_t *p_info)
{
+ (void)context;
+
psa_status_t status;
/* Check that the UID is valid */
@@ -238,6 +242,8 @@ static psa_status_t sfs_get_info(void *context, uint32_t client_id, uint64_t uid
static psa_status_t sfs_remove(void *context, uint32_t client_id, uint64_t uid)
{
+ (void)context;
+
psa_status_t status;
/* Check that the UID is valid */
@@ -270,35 +276,13 @@ static psa_status_t sfs_create(void *context,
size_t capacity,
uint32_t create_flags)
{
- psa_status_t status;
-
- /* Check that the UID is valid */
- if (uid == SFS_INVALID_UID) {
- return PSA_ERROR_INVALID_ARGUMENT;
- }
-
- /* Check that the create_flags does not contain any unsupported flags */
- if (create_flags & ~(PSA_STORAGE_FLAG_WRITE_ONCE |
- PSA_STORAGE_FLAG_NO_CONFIDENTIALITY |
- PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION)) {
- return PSA_ERROR_NOT_SUPPORTED;
- }
-
- /* Set file id */
- sfs_get_fid(client_id, uid, g_fid);
-
- /* Read file info */
- status = sfs_flash_fs_file_get_info(&fs_ctx_sfs, g_fid, &g_file_info);
- if (status == PSA_SUCCESS) {
- return PSA_ERROR_ALREADY_EXISTS;
- }
-
- /* Create the file in the file system */
- status = sfs_flash_fs_file_create(&fs_ctx_sfs, g_fid, capacity,
- 0, (uint32_t)create_flags,
- NULL);
+ (void)context;
+ (void)client_id;
+ (void)uid;
+ (void)capacity;
+ (void)create_flags;
- return status;
+ return PSA_ERROR_NOT_SUPPORTED;
}
static psa_status_t sfs_set_extended(void *context,
@@ -328,14 +312,13 @@ static uint32_t sfs_get_support(void *context, uint32_t client_id)
return 0;
}
-
-struct storage_backend *sfs_init(void)
+struct storage_backend *sfs_init(const struct sfs_flash_info_t *flash_binding)
{
psa_status_t status;
/* Initialise the SFS context */
- status = sfs_flash_fs_prepare(&fs_ctx_sfs,
- sfs_flash_get_info());
+ status = sfs_flash_fs_prepare(&fs_ctx_sfs, flash_binding);
+
#ifdef SFS_CREATE_FLASH_LAYOUT
/* If SFS_CREATE_FLASH_LAYOUT is set, it indicates that it is required to
* create a SFS flash layout. SFS service will generate an empty and valid
@@ -358,8 +341,7 @@ struct storage_backend *sfs_init(void)
}
/* Attempt to initialise again */
- status = sfs_flash_fs_prepare(&fs_ctx_sfs,
- sfs_flash_get_info());
+ status = sfs_flash_fs_prepare(&fs_ctx_sfs, flash_binding);
if (status != PSA_SUCCESS) {
return NULL;
diff --git a/components/service/secure_storage/backend/secure_flash_store/secure_flash_store.h b/components/service/secure_storage/backend/secure_flash_store/secure_flash_store.h
index ac8d9b6b4..cf6d680da 100644
--- a/components/service/secure_storage/backend/secure_flash_store/secure_flash_store.h
+++ b/components/service/secure_storage/backend/secure_flash_store/secure_flash_store.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -14,12 +14,15 @@
extern "C" {
#endif
+struct sfs_flash_info_t;
+
/**
* \brief Initializes the secure flash store backend
*
+ * \param[in] flash_binding Binding to the flash driver
* \return Pointer to storage backend or NULL on failure
*/
-struct storage_backend *sfs_init(void);
+struct storage_backend *sfs_init(const struct sfs_flash_info_t *flash_binding);
#ifdef __cplusplus
}
diff --git a/components/service/secure_storage/backend/secure_flash_store/test/component.cmake b/components/service/secure_storage/backend/secure_flash_store/test/component.cmake
index 67a621124..3c161e62a 100644
--- a/components/service/secure_storage/backend/secure_flash_store/test/component.cmake
+++ b/components/service/secure_storage/backend/secure_flash_store/test/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,6 +9,6 @@ if (NOT DEFINED TGT)
endif()
target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/sfs_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/sfs_ram_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/sfs_block_store_tests.cpp"
)
-
diff --git a/components/service/secure_storage/backend/secure_flash_store/test/sfs_block_store_tests.cpp b/components/service/secure_storage/backend/secure_flash_store/test/sfs_block_store_tests.cpp
new file mode 100644
index 000000000..ec8dbd6bd
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_flash_store/test/sfs_block_store_tests.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <service/secure_storage/frontend/psa/its/its_frontend.h>
+#include <service/secure_storage/frontend/psa/its/test/its_api_tests.h>
+#include <service/secure_storage/frontend/psa/ps/ps_frontend.h>
+#include <service/secure_storage/frontend/psa/ps/test/ps_api_tests.h>
+#include <service/secure_storage/backend/secure_flash_store/secure_flash_store.h>
+#include <service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.h>
+#include <service/block_storage/factory/ref_ram/block_store_factory.h>
+#include <service/block_storage/config/ref/ref_partition_configurator.h>
+
+/**
+ * Tests the secure flash store with a block_store flash driver.
+ */
+TEST_GROUP(SfsBlockStoreTests)
+{
+ void setup()
+ {
+ struct uuid_octets guid;
+ const struct sfs_flash_info_t *flash_info = NULL;
+
+ uuid_guid_octets_from_canonical(&guid, REF_PARTITION_2_GUID);
+
+ block_store = ref_ram_block_store_factory_create();
+ CHECK_TRUE(block_store);
+
+ psa_status_t status = sfs_flash_block_store_adapter_init(
+ &sfs_flash_adapter,
+ CLIENT_ID,
+ block_store,
+ &guid,
+ MIN_FLASH_BLOCK_SIZE,
+ MAX_NUM_FILES,
+ &flash_info);
+
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ CHECK_TRUE(flash_info);
+
+ struct storage_backend *storage_backend = sfs_init(flash_info);
+ CHECK_TRUE(storage_backend);
+
+ psa_its_frontend_init(storage_backend);
+ psa_ps_frontend_init(storage_backend);
+ }
+
+ void teardown()
+ {
+ sfs_flash_block_store_adapter_deinit(&sfs_flash_adapter);
+ ref_ram_block_store_factory_destroy(block_store);
+
+ block_store = NULL;
+ }
+
+ static const uint32_t CLIENT_ID = 10;
+ static const size_t MAX_NUM_FILES = 10;
+ static const size_t MIN_FLASH_BLOCK_SIZE = 4096;
+
+ struct block_store *block_store;
+ struct sfs_flash_block_store_adapter sfs_flash_adapter;
+};
+
+TEST(SfsBlockStoreTests, itsStoreNewItem)
+{
+ its_api_tests::storeNewItem();
+}
+
+TEST(SfsBlockStoreTests, itsStorageLimitTest)
+{
+ its_api_tests::storageLimitTest(5000);
+}
+
+TEST(SfsBlockStoreTests, psSet)
+{
+ ps_api_tests::set();
+}
+
+TEST(SfsBlockStoreTests, psCreateAndSetExtended)
+{
+ ps_api_tests::createAndSetExtended();
+}
diff --git a/components/service/secure_storage/backend/secure_flash_store/test/sfs_tests.cpp b/components/service/secure_storage/backend/secure_flash_store/test/sfs_ram_tests.cpp
index 33bdcde67..52db6393c 100644
--- a/components/service/secure_storage/backend/secure_flash_store/test/sfs_tests.cpp
+++ b/components/service/secure_storage/backend/secure_flash_store/test/sfs_ram_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,35 +10,38 @@
#include <service/secure_storage/frontend/psa/ps/ps_frontend.h>
#include <service/secure_storage/frontend/psa/ps/test/ps_api_tests.h>
#include <service/secure_storage/backend/secure_flash_store/secure_flash_store.h>
+#include <service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.h>
-
-TEST_GROUP(SfsTests)
+/**
+ * Tests the secure flash store with a ram flash driver.
+ */
+TEST_GROUP(SfsRamTests)
{
void setup()
{
- struct storage_backend *storage_backend = sfs_init();
+ struct storage_backend *storage_backend = sfs_init(sfs_flash_ram_instance());
psa_its_frontend_init(storage_backend);
psa_ps_frontend_init(storage_backend);
}
};
-TEST(SfsTests, itsStoreNewItem)
+TEST(SfsRamTests, itsStoreNewItem)
{
its_api_tests::storeNewItem();
}
-TEST(SfsTests, itsStorageLimitTest)
+TEST(SfsRamTests, itsStorageLimitTest)
{
its_api_tests::storageLimitTest(5000);
}
-TEST(SfsTests, psCreateAndSet)
+TEST(SfsRamTests, Set)
{
- ps_api_tests::createAndSet();
+ ps_api_tests::set();
}
-TEST(SfsTests, psCreateAndSetExtended)
+TEST(SfsRamTests, psCreateAndSetExtended)
{
ps_api_tests::createAndSetExtended();
}
diff --git a/components/service/secure_storage/backend/secure_storage_client/secure_storage_client.c b/components/service/secure_storage/backend/secure_storage_client/secure_storage_client.c
index cd7c1472e..b94fc4150 100644
--- a/components/service/secure_storage/backend/secure_storage_client/secure_storage_client.c
+++ b/components/service/secure_storage/backend/secure_storage_client/secure_storage_client.c
@@ -1,33 +1,35 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "secure_storage_client.h"
-#include <protocols/service/secure_storage/packed-c/secure_storage_proto.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <rpc_caller.h>
+#include "protocols/service/secure_storage/packed-c/secure_storage_proto.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "rpc_caller_session.h"
+#include "util.h"
#include <string.h>
-
static psa_status_t secure_storage_client_set(void *context,
- uint32_t client_id,
- psa_storage_uid_t uid,
- size_t data_length,
- const void *p_data,
- psa_storage_create_flags_t create_flags)
+ uint32_t client_id,
+ psa_storage_uid_t uid,
+ size_t data_length,
+ const void *p_data,
+ psa_storage_create_flags_t create_flags)
{
- struct secure_storage_client *this_context = (struct secure_storage_client*)context;
- uint8_t *request;
- uint8_t *response;
+ struct secure_storage_client *this_context = (struct secure_storage_client *)context;
+ uint8_t *request = NULL;
+ uint8_t *response = NULL;
size_t request_length = 0;
size_t response_length = 0;
- struct secure_storage_request_set *request_desc;
- rpc_call_handle handle;
- psa_status_t psa_status = PSA_SUCCESS;
+ struct secure_storage_request_set *request_desc = NULL;
+ rpc_call_handle handle = 0;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ service_status_t service_status = 0;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
- this_context->client.rpc_status = TS_RPC_CALL_ACCEPTED;
+ this_context->client.rpc_status = RPC_SUCCESS;
(void)client_id;
@@ -35,64 +37,52 @@ static psa_status_t secure_storage_client_set(void *context,
if (p_data == NULL && data_length != 0)
return PSA_ERROR_INVALID_ARGUMENT;
- request_length = sizeof(*request_desc) + data_length;
- if (request_length < data_length) {
- /* size_t overflow */
+ if (ADD_OVERFLOW(sizeof(*request_desc), data_length, &request_length))
return PSA_ERROR_INVALID_ARGUMENT;
- }
- handle = rpc_caller_begin(this_context->client.caller, &request, request_length);
-
- if (handle) {
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
-
- /* Populating request descriptor */
- request_desc = (struct secure_storage_request_set *)request;
- request_desc->uid = uid;
- request_desc->data_length = data_length;
- request_desc->create_flags = create_flags;
- memcpy(&request_desc->p_data, p_data, data_length);
-
- this_context->client.rpc_status = rpc_caller_invoke(this_context->client.caller,
- handle,
- TS_SECURE_STORAGE_OPCODE_SET,
- &opstatus, &response,
- &response_length);
-
- if (this_context->client.rpc_status != TS_RPC_CALL_ACCEPTED) {
- /* RPC failure */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
- else {
- psa_status = opstatus;
- }
-
- rpc_caller_end(this_context->client.caller, handle);
- }
- else {
+ handle = rpc_caller_session_begin(this_context->client.session, &request, request_length,
+ 0);
+ if (!handle)
+ goto out;
+
+ /* Populating request descriptor */
+ request_desc = (struct secure_storage_request_set *)request;
+ request_desc->uid = uid;
+ request_desc->data_length = data_length;
+ request_desc->create_flags = create_flags;
+ memcpy(&request_desc->p_data, p_data, data_length);
+
+ rpc_status = rpc_caller_session_invoke(handle, TS_SECURE_STORAGE_OPCODE_SET,
+ &response, &response_length, &service_status);
+ if (rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
+
+ rpc_status = rpc_caller_session_end(handle);
+ if (psa_status == PSA_SUCCESS && rpc_status != RPC_SUCCESS)
psa_status = PSA_ERROR_GENERIC_ERROR;
- }
+out:
return psa_status;
}
static psa_status_t secure_storage_client_get(void *context,
- uint32_t client_id,
- psa_storage_uid_t uid,
- size_t data_offset,
- size_t data_size,
- void *p_data,
- size_t *p_data_length)
+ uint32_t client_id,
+ psa_storage_uid_t uid,
+ size_t data_offset,
+ size_t data_size,
+ void *p_data,
+ size_t *p_data_length)
{
struct secure_storage_client *this_context = (struct secure_storage_client*)context;
- uint8_t *request;
- uint8_t *response;
+ uint8_t *request = NULL;
+ uint8_t *response = NULL;
size_t response_length = 0;
- struct secure_storage_request_get *request_desc;
- rpc_call_handle handle;
- psa_status_t psa_status = PSA_SUCCESS;
-
- this_context->client.rpc_status = TS_RPC_CALL_ACCEPTED;
+ size_t expected_response_length = data_size;
+ struct secure_storage_request_get *request_desc = NULL;
+ rpc_call_handle handle = 0;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ service_status_t service_status = 0;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
(void)client_id;
@@ -100,43 +90,37 @@ static psa_status_t secure_storage_client_get(void *context,
if (p_data == NULL && data_size != 0)
return PSA_ERROR_INVALID_ARGUMENT;
- handle = rpc_caller_begin(this_context->client.caller, &request, sizeof(*request_desc));
-
- if (handle) {
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
-
- /* Populating request descriptor */
- request_desc = (struct secure_storage_request_get *)request;
- request_desc->uid = uid;
- request_desc->data_offset = data_offset;
- request_desc->data_size = data_size;
-
- this_context->client.rpc_status = rpc_caller_invoke(this_context->client.caller,
- handle,
- TS_SECURE_STORAGE_OPCODE_GET,
- &opstatus, &response,
- &response_length);
-
- if (this_context->client.rpc_status != TS_RPC_CALL_ACCEPTED ) {
- /* RPC failure */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
- else {
- psa_status = opstatus;
- }
-
- /* Filling output parameters */
- if (psa_status == PSA_SUCCESS) {
- *p_data_length = (response_length <= data_size) ? response_length : data_size;
- memcpy(p_data, response, *p_data_length);
- }
-
- rpc_caller_end(this_context->client.caller, handle);
- }
- else {
+ handle = rpc_caller_session_begin(this_context->client.session, &request,
+ sizeof(*request_desc), expected_response_length);
+ if (!handle)
+ goto out;
+
+ /* Populating request descriptor */
+ request_desc = (struct secure_storage_request_get *)request;
+ request_desc->uid = uid;
+ request_desc->data_offset = data_offset;
+ request_desc->data_size = data_size;
+
+ rpc_status = rpc_caller_session_invoke(handle, TS_SECURE_STORAGE_OPCODE_GET, &response,
+ &response_length, &service_status);
+ if (rpc_status != RPC_SUCCESS || response_length > data_size)
+ goto session_end;
+
+ psa_status = service_status;
+
+ /* Filling output parameters */
+ if (psa_status != PSA_SUCCESS)
+ goto session_end;
+
+ *p_data_length = response_length;
+ memcpy(p_data, response, response_length);
+
+session_end:
+ rpc_status = rpc_caller_session_end(handle);
+ if (psa_status == PSA_SUCCESS && rpc_status != RPC_SUCCESS)
psa_status = PSA_ERROR_GENERIC_ERROR;
- }
+out:
return psa_status;
}
@@ -146,12 +130,14 @@ static psa_status_t secure_storage_client_get_info(void *context,
struct psa_storage_info_t *p_info)
{
struct secure_storage_client *this_context = (struct secure_storage_client*)context;
- uint8_t *request;
- uint8_t *response;
+ uint8_t *request = NULL;
+ uint8_t *response = NULL;
size_t response_length = 0;
- struct secure_storage_request_get_info *request_desc;
- struct secure_storage_response_get_info *response_desc;
- rpc_call_handle handle;
+ struct secure_storage_request_get_info *request_desc = NULL;
+ struct secure_storage_response_get_info *response_desc = NULL;
+ rpc_call_handle handle = 0;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ service_status_t service_status = 0;
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
(void)client_id;
@@ -160,151 +146,120 @@ static psa_status_t secure_storage_client_get_info(void *context,
if (p_info == NULL)
return PSA_ERROR_INVALID_ARGUMENT;
- handle = rpc_caller_begin(this_context->client.caller, &request, sizeof(*request_desc));
-
- if (handle) {
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
-
- /* Populating request descriptor */
- request_desc = (struct secure_storage_request_get_info *)request;
- request_desc->uid = uid;
-
- this_context->client.rpc_status = rpc_caller_invoke(this_context->client.caller, handle,
- TS_SECURE_STORAGE_OPCODE_GET_INFO,
- &opstatus, &response,
- &response_length);
-
- if (this_context->client.rpc_status != TS_RPC_CALL_ACCEPTED) {
- /* RPC failure */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- } else {
- if (response_length && response_length != sizeof(*response_desc)) {
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
- else {
- psa_status = opstatus;
- }
- }
-
- if (psa_status == PSA_SUCCESS) {
- response_desc = (struct secure_storage_response_get_info *)response;
- p_info->capacity = response_desc->capacity;
- p_info->size = response_desc->size;
- p_info->flags = response_desc->flags;
- } else {
- p_info->capacity = 0;
- p_info->size = 0;
- p_info->flags = PSA_STORAGE_FLAG_NONE;
- }
-
- rpc_caller_end(this_context->client.caller, handle);
+ handle = rpc_caller_session_begin(this_context->client.session, &request,
+ sizeof(*request_desc), sizeof(*response_desc));
+ if (!handle)
+ goto out;
+
+ /* Populating request descriptor */
+ request_desc = (struct secure_storage_request_get_info *)request;
+ request_desc->uid = uid;
+
+ rpc_status = rpc_caller_session_invoke(handle, TS_SECURE_STORAGE_OPCODE_GET_INFO,
+ &response, &response_length, &service_status);
+ if (rpc_status != RPC_SUCCESS ||
+ (service_status == PSA_SUCCESS && response_length != sizeof(*response_desc)))
+ goto session_end;
+
+ psa_status = service_status;
+
+ if (psa_status == PSA_SUCCESS) {
+ response_desc = (struct secure_storage_response_get_info *)response;
+
+ p_info->capacity = response_desc->capacity;
+ p_info->size = response_desc->size;
+ p_info->flags = response_desc->flags;
+ } else {
+ p_info->capacity = 0;
+ p_info->size = 0;
+ p_info->flags = PSA_STORAGE_FLAG_NONE;
}
- else {
+
+session_end:
+ rpc_status = rpc_caller_session_end(handle);
+ if (psa_status == PSA_SUCCESS && rpc_status != RPC_SUCCESS)
psa_status = PSA_ERROR_GENERIC_ERROR;
- }
+out:
return psa_status;
}
static psa_status_t secure_storage_client_remove(void *context,
- uint32_t client_id,
- psa_storage_uid_t uid)
+ uint32_t client_id,
+ psa_storage_uid_t uid)
{
struct secure_storage_client *this_context = (struct secure_storage_client*)context;
- uint8_t *request;
- uint8_t *response;
+ uint8_t *request = NULL;
+ uint8_t *response = NULL;
size_t response_length = 0;
- struct secure_storage_request_remove *request_desc;
- rpc_call_handle handle;
- psa_status_t psa_status = PSA_SUCCESS;
-
- this_context->client.rpc_status = TS_RPC_CALL_ACCEPTED;
+ struct secure_storage_request_remove *request_desc = NULL;
+ rpc_call_handle handle = 0;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ service_status_t service_status = 0;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
(void)client_id;
- handle = rpc_caller_begin(this_context->client.caller, &request, sizeof(*request_desc));
+ handle = rpc_caller_session_begin(this_context->client.session, &request,
+ sizeof(*request_desc), 0);
+ if (!handle)
+ goto out;
- if (handle) {
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
+ /* Populating request descriptor */
+ request_desc = (struct secure_storage_request_remove *)request;
+ request_desc->uid = uid;
- /* Populating request descriptor */
- request_desc = (struct secure_storage_request_remove *)request;
- request_desc->uid = uid;
+ rpc_status = rpc_caller_session_invoke(handle, TS_SECURE_STORAGE_OPCODE_REMOVE,
+ &response, &response_length, &service_status);
+ if (rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- this_context->client.rpc_status = rpc_caller_invoke(this_context->client.caller,
- handle,
- TS_SECURE_STORAGE_OPCODE_REMOVE,
- &opstatus, &response,
- &response_length);
-
- if (this_context->client.rpc_status != TS_RPC_CALL_ACCEPTED) {
- /* RPC failure */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
- else {
- psa_status = opstatus;
- }
-
- rpc_caller_end(this_context->client.caller, handle);
- }
- else {
+ rpc_status = rpc_caller_session_end(handle);
+ if (psa_status == PSA_SUCCESS && rpc_status != RPC_SUCCESS)
psa_status = PSA_ERROR_GENERIC_ERROR;
- }
+out:
return psa_status;
}
static psa_status_t secure_storage_client_create(void *context,
- uint32_t client_id,
- uint64_t uid,
- size_t capacity,
- uint32_t create_flags)
+ uint32_t client_id,
+ uint64_t uid,
+ size_t capacity,
+ uint32_t create_flags)
{
struct secure_storage_client *this_context = (struct secure_storage_client*)context;
- uint8_t *request;
- uint8_t *response;
- size_t request_length = 0;
+ uint8_t *request = NULL;
+ uint8_t *response = NULL;
size_t response_length = 0;
- struct secure_storage_request_create *request_desc;
- rpc_call_handle handle;
+ struct secure_storage_request_create *request_desc = NULL;
+ rpc_call_handle handle = 0;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ service_status_t service_status = 0;
psa_status_t psa_status = PSA_SUCCESS;
- this_context->client.rpc_status = TS_RPC_CALL_ACCEPTED;
-
(void)client_id;
- request_length = sizeof(*request_desc);
-
- handle = rpc_caller_begin(this_context->client.caller, &request, request_length);
-
- if (handle) {
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
-
- request_desc = (struct secure_storage_request_create*)request;
- request_desc->uid = uid;
- request_desc->capacity = capacity;
- request_desc->create_flags = create_flags;
+ handle = rpc_caller_session_begin(this_context->client.session, &request,
+ sizeof(*request_desc), 0);
+ if (!handle)
+ goto out;
- this_context->client.rpc_status = rpc_caller_invoke(this_context->client.caller,
- handle,
- TS_SECURE_STORAGE_OPCODE_CREATE,
- &opstatus, &response,
- &response_length);
+ request_desc = (struct secure_storage_request_create *)request;
+ request_desc->uid = uid;
+ request_desc->capacity = capacity;
+ request_desc->create_flags = create_flags;
- if (this_context->client.rpc_status != TS_RPC_CALL_ACCEPTED) {
- /* RPC failure */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
- else {
- psa_status = opstatus;
- }
+ rpc_status = rpc_caller_session_invoke(handle, TS_SECURE_STORAGE_OPCODE_CREATE,
+ &response, &response_length, &service_status);
+ if (rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
- rpc_caller_end(this_context->client.caller, handle);
- }
- else {
+ rpc_status = rpc_caller_session_end(handle);
+ if (psa_status == PSA_SUCCESS && rpc_status != RPC_SUCCESS)
psa_status = PSA_ERROR_GENERIC_ERROR;
- }
+out:
return psa_status;
}
@@ -316,115 +271,94 @@ static psa_status_t secure_storage_set_extended(void *context,
const void *p_data)
{
struct secure_storage_client *this_context = (struct secure_storage_client*)context;
- uint8_t *request;
- uint8_t *response;
+ uint8_t *request = NULL;
+ uint8_t *response = NULL;
size_t request_length = 0;
size_t response_length = 0;
- struct secure_storage_request_set_extended *request_desc;
- rpc_call_handle handle;
+ struct secure_storage_request_set_extended *request_desc = NULL;
+ rpc_call_handle handle = 0;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ service_status_t service_status = 0;
psa_status_t psa_status = PSA_SUCCESS;
- this_context->client.rpc_status = TS_RPC_CALL_ACCEPTED;
-
(void)client_id;
/* Validating input parameters */
if (p_data == NULL)
return PSA_ERROR_INVALID_ARGUMENT;
- request_length = sizeof(*request_desc) + data_length;
- if (request_length < data_length) {
- /* size_t overflow */
+ if (ADD_OVERFLOW(sizeof(*request_desc), data_length, &request_length))
return PSA_ERROR_INVALID_ARGUMENT;
- }
- handle = rpc_caller_begin(this_context->client.caller, &request, request_length);
-
- if (handle) {
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
-
- /* Populating request descriptor */
- request_desc = (struct secure_storage_request_set_extended *)request;
- request_desc->uid = uid;
- request_desc->data_offset = data_offset;
- request_desc->data_length = data_length;
- memcpy(&request_desc->p_data, p_data, data_length);
-
- this_context->client.rpc_status = rpc_caller_invoke(this_context->client.caller,
- handle,
- TS_SECURE_STORAGE_OPCODE_SET_EXTENDED,
- &opstatus, &response,
- &response_length);
-
- if (this_context->client.rpc_status != TS_RPC_CALL_ACCEPTED) {
- /* RPC failure */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
- else {
- psa_status = opstatus;
- }
-
- rpc_caller_end(this_context->client.caller, handle);
- }
- else {
+ handle = rpc_caller_session_begin(this_context->client.session, &request, request_length,
+ 0);
+ if (!handle)
+ goto out;
+
+ /* Populating request descriptor */
+ request_desc = (struct secure_storage_request_set_extended *)request;
+ request_desc->uid = uid;
+ request_desc->data_offset = data_offset;
+ request_desc->data_length = data_length;
+ memcpy(&request_desc->p_data, p_data, data_length);
+
+ rpc_status = rpc_caller_session_invoke(handle, TS_SECURE_STORAGE_OPCODE_SET_EXTENDED,
+ &response, &response_length, &service_status);
+ if (rpc_status == RPC_SUCCESS)
+ psa_status = service_status;
+
+ rpc_status = rpc_caller_session_end(handle);
+ if (psa_status == PSA_SUCCESS && rpc_status != RPC_SUCCESS)
psa_status = PSA_ERROR_GENERIC_ERROR;
- }
+out:
return psa_status;
}
static uint32_t secure_storage_get_support(void *context, uint32_t client_id)
{
struct secure_storage_client *this_context = (struct secure_storage_client*)context;
- uint8_t *request;
- uint8_t *response;
+ uint8_t *request = NULL;
+ uint8_t *response = NULL;
size_t response_length = 0;
- struct secure_storage_response_get_support *response_desc;
- rpc_call_handle handle;
+ struct secure_storage_response_get_support *response_desc = NULL;
+ rpc_call_handle handle = 0;
psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ service_status_t service_status = 0;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
uint32_t feature_map = 0;
(void)client_id;
- handle = rpc_caller_begin(this_context->client.caller, &request, 0);
-
- if (handle) {
- rpc_opstatus_t opstatus = PSA_ERROR_GENERIC_ERROR;
-
- this_context->client.rpc_status = rpc_caller_invoke(this_context->client.caller,
- handle,
- TS_SECURE_STORAGE_OPCODE_GET_SUPPORT,
- &opstatus, &response,
- &response_length);
-
- if (this_context->client.rpc_status != TS_RPC_CALL_ACCEPTED) {
- /* RPC failure */
- psa_status = PSA_ERROR_GENERIC_ERROR;
- } else {
- if (response_length < sizeof(*response_desc)) {
- psa_status = PSA_ERROR_GENERIC_ERROR;
- }
- else {
- psa_status = opstatus;
- }
- }
-
- if (psa_status == PSA_SUCCESS) {
- response_desc = (struct secure_storage_response_get_support*)response;
- feature_map = response_desc->support;
- }
-
- rpc_caller_end(this_context->client.caller, handle);
- }
+ handle = rpc_caller_session_begin(this_context->client.session, &request, 0,
+ sizeof(*response_desc));
+ if (!handle)
+ goto out;
+
+ rpc_status = rpc_caller_session_invoke(handle, TS_SECURE_STORAGE_OPCODE_GET_SUPPORT,
+ &response, &response_length, &service_status);
+ if (rpc_status != RPC_SUCCESS || response_length < sizeof(*response_desc))
+ goto session_end;
+
+ psa_status = service_status;
+ if (psa_status != PSA_SUCCESS)
+ goto session_end;
+
+ response_desc = (struct secure_storage_response_get_support *)response;
+ feature_map = response_desc->support;
+
+session_end:
+ rpc_caller_session_end(handle);
+out:
return feature_map;
}
struct storage_backend *secure_storage_client_init(struct secure_storage_client *context,
- struct rpc_caller *caller)
+ struct rpc_caller_session *session)
{
- service_client_init(&context->client, caller);
+ service_client_init(&context->client, session);
static const struct storage_backend_interface interface =
{
diff --git a/components/service/secure_storage/backend/secure_storage_client/secure_storage_client.h b/components/service/secure_storage/backend/secure_storage_client/secure_storage_client.h
index cb90e6295..28f15f842 100644
--- a/components/service/secure_storage/backend/secure_storage_client/secure_storage_client.h
+++ b/components/service/secure_storage/backend/secure_storage_client/secure_storage_client.h
@@ -36,7 +36,7 @@ struct secure_storage_client
* @return Pointer to inialized storage backend or NULL on failure
*/
struct storage_backend *secure_storage_client_init(struct secure_storage_client *context,
- struct rpc_caller *caller);
+ struct rpc_caller_session *session);
/**
* @brief Deinitialize a secure storage client
diff --git a/components/service/secure_storage/backend/secure_storage_client/test/secure_storage_client_tests.cpp b/components/service/secure_storage/backend/secure_storage_client/test/secure_storage_client_tests.cpp
index 7cd887ee3..b3036cef8 100644
--- a/components/service/secure_storage/backend/secure_storage_client/test/secure_storage_client_tests.cpp
+++ b/components/service/secure_storage/backend/secure_storage_client/test/secure_storage_client_tests.cpp
@@ -6,6 +6,7 @@
#include <CppUTest/TestHarness.h>
#include <rpc/direct/direct_caller.h>
+#include "service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
#include <service/secure_storage/frontend/psa/its/its_frontend.h>
#include <service/secure_storage/frontend/psa/its/test/its_api_tests.h>
#include <service/secure_storage/frontend/psa/ps/ps_frontend.h>
@@ -23,14 +24,23 @@ TEST_GROUP(SecureStorageClientTests)
*/
void setup()
{
+ struct rpc_uuid service_uuid = { .uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID };
struct storage_backend *storage_provider_backend =
mock_store_init(&m_mock_store);
- struct rpc_interface *storage_ep =
- secure_storage_provider_init(&m_storage_provider, storage_provider_backend);
- struct rpc_caller *storage_caller =
- direct_caller_init_default(&m_storage_caller, storage_ep);
+ struct rpc_service_interface *storage_ep =
+ secure_storage_provider_init(&m_storage_provider, storage_provider_backend,
+ &service_uuid);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ rpc_status = direct_caller_init(&m_storage_caller, storage_ep);
+ CHECK_EQUAL(RPC_SUCCESS, rpc_status);
+
+ rpc_status = rpc_caller_session_find_and_open(&m_storage_session, &m_storage_caller,
+ &service_uuid, 4096);
+ CHECK_EQUAL(RPC_SUCCESS, rpc_status);
+
struct storage_backend *storage_client_backend =
- secure_storage_client_init(&m_storage_client, storage_caller);
+ secure_storage_client_init(&m_storage_client, &m_storage_session);
psa_its_frontend_init(storage_client_backend);
psa_ps_frontend_init(storage_client_backend);
@@ -41,13 +51,15 @@ TEST_GROUP(SecureStorageClientTests)
mock_store_deinit(&m_mock_store);
secure_storage_provider_deinit(&m_storage_provider);
secure_storage_client_deinit(&m_storage_client);
+ rpc_caller_session_close(&m_storage_session);
direct_caller_deinit(&m_storage_caller);
}
struct mock_store m_mock_store;
struct secure_storage_provider m_storage_provider;
struct secure_storage_client m_storage_client;
- struct direct_caller m_storage_caller;
+ struct rpc_caller_interface m_storage_caller;
+ struct rpc_caller_session m_storage_session;
};
TEST(SecureStorageClientTests, itsStoreNewItem)
@@ -60,9 +72,9 @@ TEST(SecureStorageClientTests, itsStorageLimitTest)
its_api_tests::storageLimitTest(MOCK_STORE_ITEM_SIZE_LIMIT);
}
-TEST(SecureStorageClientTests, psCreateAndSet)
+TEST(SecureStorageClientTests, psSet)
{
- ps_api_tests::createAndSet();
+ ps_api_tests::set();
}
TEST(SecureStorageClientTests, psCreateAndSetExtended)
diff --git a/components/service/secure_storage/backend/secure_storage_client/test/secure_storage_proxy_tests.cpp b/components/service/secure_storage/backend/secure_storage_client/test/secure_storage_proxy_tests.cpp
index c0287764a..953210c58 100644
--- a/components/service/secure_storage/backend/secure_storage_client/test/secure_storage_proxy_tests.cpp
+++ b/components/service/secure_storage/backend/secure_storage_client/test/secure_storage_proxy_tests.cpp
@@ -6,6 +6,7 @@
#include <CppUTest/TestHarness.h>
#include <rpc/direct/direct_caller.h>
+#include "service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
#include <service/secure_storage/frontend/psa/its/its_frontend.h>
#include <service/secure_storage/frontend/psa/its/test/its_api_tests.h>
#include <service/secure_storage/frontend/psa/ps/ps_frontend.h>
@@ -24,25 +25,35 @@ TEST_GROUP(SecureStorageProxyTests)
*/
void setup()
{
+ struct rpc_uuid service_uuid = { .uuid = TS_PSA_PROTECTED_STORAGE_UUID };
/* Initialise the actual storage provider */
struct storage_backend *storage_provider_backend =
mock_store_init(&m_mock_store);
- struct rpc_interface *storage_ep =
- secure_storage_provider_init(&m_storage_provider, storage_provider_backend);
- struct rpc_caller *storage_caller =
- direct_caller_init_default(&m_storage_caller, storage_ep);
+ struct rpc_service_interface *storage_ep =
+ secure_storage_provider_init(&m_storage_provider, storage_provider_backend,
+ &service_uuid);
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ rpc_status = direct_caller_init(&m_storage_caller, storage_ep);
+ CHECK_EQUAL(RPC_SUCCESS, rpc_status);
+
+ rpc_status = rpc_caller_session_find_and_open(&m_storage_session, &m_storage_caller,
+ &service_uuid, 4096);
+ CHECK_EQUAL(RPC_SUCCESS, rpc_status);
/* Initialise the intermediate proxy */
struct storage_backend *proxy_backend =
- secure_storage_client_init(&m_proxy_client, storage_caller);
- struct rpc_interface *proxy_ep =
- secure_storage_provider_init(&m_proxy_provider, proxy_backend);
- struct rpc_caller *proxy_caller =
- direct_caller_init_default(&m_proxy_caller, proxy_ep);
+ secure_storage_client_init(&m_proxy_client, &m_storage_session);
+ struct rpc_service_interface *proxy_ep =
+ secure_storage_provider_init(&m_proxy_provider, proxy_backend, &service_uuid);
+ direct_caller_init(&m_proxy_caller, proxy_ep);
+
+ rpc_caller_session_find_and_open(&m_proxy_session, &m_proxy_caller, &service_uuid,
+ 4096);
/* Initialise the client-side backend that talks to the proxy */
struct storage_backend *storage_client_backend =
- secure_storage_client_init(&m_storage_client, proxy_caller);
+ secure_storage_client_init(&m_storage_client, &m_proxy_session);
psa_its_frontend_init(storage_client_backend);
psa_ps_frontend_init(storage_client_backend);
@@ -58,6 +69,9 @@ TEST_GROUP(SecureStorageProxyTests)
secure_storage_client_deinit(&m_storage_client);
+ rpc_caller_session_close(&m_proxy_session);
+ rpc_caller_session_close(&m_storage_session);
+
direct_caller_deinit(&m_proxy_caller);
direct_caller_deinit(&m_storage_caller);
}
@@ -67,8 +81,10 @@ TEST_GROUP(SecureStorageProxyTests)
struct secure_storage_client m_proxy_client;
struct secure_storage_provider m_proxy_provider;
struct secure_storage_client m_storage_client;
- struct direct_caller m_storage_caller;
- struct direct_caller m_proxy_caller;
+ struct rpc_caller_interface m_storage_caller;
+ struct rpc_caller_interface m_proxy_caller;
+ struct rpc_caller_session m_storage_session;
+ struct rpc_caller_session m_proxy_session;
};
TEST(SecureStorageProxyTests, itsStoreNewItem)
@@ -81,9 +97,9 @@ TEST(SecureStorageProxyTests, itsStorageLimitTest)
its_api_tests::storageLimitTest(MOCK_STORE_ITEM_SIZE_LIMIT);
}
-TEST(SecureStorageProxyTests, psCreateAndSet)
+TEST(SecureStorageProxyTests, psSet)
{
- ps_api_tests::createAndSet();
+ ps_api_tests::set();
}
TEST(SecureStorageProxyTests, psCreateAndSetExtended)
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/component.cmake b/components/service/secure_storage/backend/secure_storage_ipc/component.cmake
new file mode 100644
index 000000000..5d8f6714e
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/secure_storage_ipc.c"
+ )
+
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
new file mode 100644
index 000000000..986628c8c
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <protocols/rpc/common/packed-c/status.h>
+#include "secure_storage_ipc.h"
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <rpc_caller.h>
+#include <string.h>
+#include <trace.h>
+
+
+static psa_status_t secure_storage_ipc_set(void *context, uint32_t client_id,
+ psa_storage_uid_t uid, size_t data_length,
+ const void *p_data, psa_storage_create_flags_t create_flags)
+{
+ struct secure_storage_ipc *ipc = context;
+ struct rpc_caller_interface *caller = ipc->client.session->caller;
+ psa_status_t psa_status;
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
+ { .base = psa_ptr_const_to_u32(p_data), .len = data_length },
+ { .base = psa_ptr_to_u32(&create_flags), .len = sizeof(create_flags) },
+ };
+
+ ipc->client.rpc_status = TS_RPC_CALL_ACCEPTED;
+
+ psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+ TFM_PS_ITS_SET, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+ if (psa_status < 0)
+ EMSG("ipc_set: psa_call failed: %d", psa_status);
+
+ return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_get(void *context,
+ uint32_t client_id,
+ psa_storage_uid_t uid,
+ size_t data_offset,
+ size_t data_size,
+ void *p_data,
+ size_t *p_data_length)
+{
+ struct secure_storage_ipc *ipc = context;
+ struct rpc_caller_interface *caller = ipc->client.session->caller;
+ psa_status_t psa_status;
+ uint32_t offset = (uint32_t)data_offset;
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
+ { .base = psa_ptr_to_u32(&offset), .len = sizeof(offset) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(p_data), .len = data_size },
+ };
+
+ if (!p_data_length) {
+ EMSG("ipc_get: p_data_length not defined");
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+ TFM_PS_ITS_GET, in_vec,
+ IOVEC_LEN(in_vec), out_vec,
+ IOVEC_LEN(out_vec));
+ if (psa_status == PSA_SUCCESS)
+ *p_data_length = out_vec[0].len;
+
+ return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_get_info(void *context,
+ uint32_t client_id,
+ psa_storage_uid_t uid,
+ struct psa_storage_info_t *p_info)
+{
+ struct secure_storage_ipc *ipc = context;
+ struct rpc_caller_interface *caller = ipc->client.session->caller;
+ psa_status_t psa_status;
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
+ };
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(p_info), .len = sizeof(*p_info) },
+ };
+
+ psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+ TFM_PS_ITS_GET_INFO, in_vec,
+ IOVEC_LEN(in_vec), out_vec,
+ IOVEC_LEN(out_vec));
+ if (psa_status != PSA_SUCCESS)
+ EMSG("ipc_get_info: failed to psa_call: %d", psa_status);
+
+ return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_remove(void *context,
+ uint32_t client_id,
+ psa_storage_uid_t uid)
+{
+ struct secure_storage_ipc *ipc = context;
+ struct rpc_caller_interface *caller = ipc->client.session->caller;
+ psa_status_t psa_status;
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
+ };
+
+ psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+ TFM_PS_ITS_REMOVE, in_vec,
+ IOVEC_LEN(in_vec), NULL, 0);
+ if (psa_status != PSA_SUCCESS)
+ EMSG("ipc_remove: failed to psa_call: %d", psa_status);
+
+ return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_create(void *context,
+ uint32_t client_id,
+ uint64_t uid,
+ size_t capacity,
+ uint32_t create_flags)
+{
+ (void)context;
+ (void)uid;
+ (void)client_id;
+ (void)capacity;
+ (void)create_flags;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static psa_status_t secure_storage_set_extended(void *context,
+ uint32_t client_id,
+ uint64_t uid,
+ size_t data_offset,
+ size_t data_length,
+ const void *p_data)
+{
+ (void)context;
+ (void)uid;
+ (void)client_id;
+ (void)data_offset;
+ (void)data_length;
+ (void)p_data;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static uint32_t secure_storage_get_support(void *context, uint32_t client_id)
+{
+ struct secure_storage_ipc *ipc = context;
+ struct rpc_caller_interface *caller = ipc->client.session->caller;
+ psa_status_t psa_status;
+ uint32_t support_flags;
+ struct psa_outvec out_vec[] = {
+ { .base = psa_ptr_to_u32(&support_flags), .len = sizeof(support_flags) },
+ };
+
+ psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+ TFM_PS_ITS_GET_SUPPORT, NULL, 0,
+ out_vec, IOVEC_LEN(out_vec));
+ if (psa_status != PSA_SUCCESS)
+ EMSG("ipc_get_support: failed to psa_call: %d", psa_status);
+
+ return psa_status;
+}
+
+struct storage_backend *secure_storage_ipc_init(struct secure_storage_ipc *context,
+ struct rpc_caller_session *session)
+{
+ service_client_init(&context->client, session);
+
+ static const struct storage_backend_interface interface =
+ {
+ .set = secure_storage_ipc_set,
+ .get = secure_storage_ipc_get,
+ .get_info = secure_storage_ipc_get_info,
+ .remove = secure_storage_ipc_remove,
+ .create = secure_storage_ipc_create,
+ .set_extended = secure_storage_set_extended,
+ .get_support = secure_storage_get_support,
+ };
+
+ context->backend.context = context;
+ context->backend.interface = &interface;
+
+ return &context->backend;
+}
+
+void secure_storage_ipc_deinit(struct secure_storage_ipc *context)
+{
+ service_client_deinit(&context->client);
+}
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h
new file mode 100644
index 000000000..33045e90b
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_STORAGE_IPC_H
+#define SECURE_STORAGE_IPC_H
+
+#include <service/secure_storage/backend/storage_backend.h>
+#include <service/common/client/service_client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Secure storage ipc instance
+ */
+struct secure_storage_ipc
+{
+ struct storage_backend backend;
+ struct service_client client;
+ int32_t service_handle;
+};
+
+/**
+ * @brief Initialize a secure storage ipc client
+ *
+ * A secure storage client is a storage backend that makes RPC calls
+ * to a remote secure storage provider.
+ *
+ * @param[in] context Instance data
+ * @param[in] rpc_caller RPC caller instance
+ *
+ *
+ * @return Pointer to inialized storage backend or NULL on failure
+ */
+struct storage_backend *secure_storage_ipc_init(struct secure_storage_ipc *context,
+ struct rpc_caller_session *session);
+
+/**
+ * @brief Deinitialize a secure storage ipc client
+ *
+ * @param[in] context Instance data
+ */
+void secure_storage_ipc_deinit(struct secure_storage_ipc *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECURE_STORAGE_IPC_H */
diff --git a/components/service/secure_storage/factory/common/sfs/storage_factory.c b/components/service/secure_storage/factory/common/sfs/storage_factory.c
index 81f708de5..ae86a05cf 100644
--- a/components/service/secure_storage/factory/common/sfs/storage_factory.c
+++ b/components/service/secure_storage/factory/common/sfs/storage_factory.c
@@ -1,13 +1,13 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
-#include <rpc/ffarpc/caller/sp/ffarpc_caller.h>
#include <protocols/rpc/common/packed-c/status.h>
#include <service/secure_storage/backend/secure_flash_store/secure_flash_store.h>
+#include <service/secure_storage/backend/secure_flash_store/flash/ram/sfs_flash_ram.h>
#include <service/secure_storage/factory/storage_factory.h>
/**
@@ -21,7 +21,7 @@ struct storage_backend *storage_factory_create(
enum storage_factory_security_class security_class)
{
(void)security_class;
- return sfs_init();
+ return sfs_init(sfs_flash_ram_instance());
}
void storage_factory_destroy(struct storage_backend *backend)
diff --git a/components/service/secure_storage/factory/sp/optee_trusted_store/storage_factory.c b/components/service/secure_storage/factory/sp/optee_trusted_store/storage_factory.c
deleted file mode 100644
index 5423af685..000000000
--- a/components/service/secure_storage/factory/sp/optee_trusted_store/storage_factory.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-/**
- * A storage factory that creates storage backends that communicate with an
- * S-EL1 partition to access trusted storage provided by OPTEE. The S-EL1
- * partition is assumed to host a conventional secure storage provider
- * that can be accessed using the secure storage access protocol.
- * Uses a default UUID to discover the S-EL1 partition if no external
- * configuration overrides this.
- */
-#include <rpc/ffarpc/caller/sp/ffarpc_caller.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <service/secure_storage/backend/secure_storage_client/secure_storage_client.h>
-#include <service/secure_storage/backend/null_store/null_store.h>
-#include <service/secure_storage/factory/storage_factory.h>
-#include <ffa_api.h>
-#include <stdbool.h>
-#include <stddef.h>
-
-/* NOTE: this is the ITS partition UUID - should be changed when S-EL1 SP is ready */
-#define OPTEE_TRUSTED_STORE_UUID_BYTES \
- { 0xdc, 0x1e, 0xef, 0x48, 0xb1, 0x7a, 0x4c, 0xcf, \
- 0xac, 0x8b, 0xdf, 0xcf, 0xf7, 0x71, 0x1b, 0x14 }
-
-static const uint8_t default_optee_trusted_store_uuid[] = OPTEE_TRUSTED_STORE_UUID_BYTES;
-
-/* The storage backed specialization constructed by this factory */
-struct optee_trusted_store
-{
- struct secure_storage_client secure_storage_client;
- struct ffarpc_caller ffarpc_caller;
- bool in_use;
-};
-
-/* Only supports construction of a single instance */
-static struct optee_trusted_store backend_instance = { .in_use = false };
-
-/* Used on failure if no association with a storage provider is established */
-static struct null_store null_store;
-
-
-struct storage_backend *storage_factory_create(
- enum storage_factory_security_class security_class)
-{
- struct rpc_caller *storage_caller;
- uint16_t storage_sp_ids[1];
- struct optee_trusted_store *new_backend = &backend_instance;
- struct storage_backend *result = NULL;
-
- if (!new_backend->in_use) {
-
- storage_caller = ffarpc_caller_init(&new_backend->ffarpc_caller);
-
- /* Try discovering candidate endpoints in preference order */
- if (ffarpc_caller_discover(default_optee_trusted_store_uuid, storage_sp_ids,
- sizeof(storage_sp_ids)/sizeof(uint16_t))) {
-
- if (ffarpc_caller_open(&new_backend->ffarpc_caller, storage_sp_ids[0], 0) == 0) {
-
- result = secure_storage_client_init(&new_backend->secure_storage_client,
- storage_caller);
- }
- }
-
- if (!result) {
-
- /* Failed to discover or open an RPC session with provider */
- ffarpc_caller_deinit(&new_backend->ffarpc_caller);
- }
-
- new_backend->in_use = (result != NULL);
- }
-
- if (!result) {
-
- /**
- * Errors during SP initialisation can be difficult to handle so
- * returns a valid storage_backend, albeit one that just returns
- * an appropriate status code if any methods are called. This
- * allows an error to be reported to a requesting client where
- * it may be easier to handle.
- */
- result = null_store_init(&null_store);
- }
-
- return result;
-}
-
-void storage_factory_destroy(struct storage_backend *backend)
-{
- if (backend) {
-
- secure_storage_client_deinit(&backend_instance.secure_storage_client);
- ffarpc_caller_deinit(&backend_instance.ffarpc_caller);
- backend_instance.in_use = false;
- }
-}
diff --git a/components/service/secure_storage/factory/sp/rot_store/storage_factory.c b/components/service/secure_storage/factory/sp/rot_store/storage_factory.c
index 9c37d4d03..ed0b999c3 100644
--- a/components/service/secure_storage/factory/sp/rot_store/storage_factory.c
+++ b/components/service/secure_storage/factory/sp/rot_store/storage_factory.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -14,34 +14,35 @@
* requested storage class is used. The availability of Internal Trusted
* and Protected stores will depend on the platform.
*/
-#include <rpc/ffarpc/caller/sp/ffarpc_caller.h>
+#include "rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.h"
+#include "rpc/common/caller/rpc_caller_session.h"
#include <protocols/rpc/common/packed-c/status.h>
#include <service/secure_storage/backend/secure_storage_client/secure_storage_client.h>
#include <service/secure_storage/backend/null_store/null_store.h>
#include <service/secure_storage/factory/storage_factory.h>
+#include "service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
#include <ffa_api.h>
+#include "sp_discovery.h"
#include <stdbool.h>
#include <stddef.h>
/* Defaults to using PSA storage partitions if no external configuration specified */
-#define ITS_STORE_UUID_BYTES \
- { 0xdc, 0x1e, 0xef, 0x48, 0xb1, 0x7a, 0x4c, 0xcf, \
- 0xac, 0x8b, 0xdf, 0xcf, 0xf7, 0x71, 0x1b, 0x14 }
-
-#define PS_STORE_UUID_BYTES \
- { 0x75, 0x1b, 0xf8, 0x01, 0x3d, 0xde, 0x47, 0x68, \
- 0xa5, 0x14, 0x0f, 0x10, 0xae, 0xed, 0x17, 0x90 }
-
#define MAX_CANDIDATE_UUIDS (2)
-static const uint8_t default_internal_store_uuid[] = ITS_STORE_UUID_BYTES;
-static const uint8_t default_protected_store_uuid[] = PS_STORE_UUID_BYTES;
+static const struct rpc_uuid default_internal_store_uuid = {
+ .uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID
+};
+
+static const struct rpc_uuid default_protected_store_uuid = {
+ .uuid = TS_PSA_PROTECTED_STORAGE_UUID
+};
/* The storage backed specialization constructed by this factory */
struct rot_store
{
struct secure_storage_client secure_storage_client;
- struct ffarpc_caller ffarpc_caller;
+ struct rpc_caller_interface caller;
+ struct rpc_caller_session session;
bool in_use;
};
@@ -51,53 +52,45 @@ static struct rot_store backend_instance = { .in_use = false };
/* Used on failure if no association with a storage provider is established */
static struct null_store null_store;
-static int select_candidate_uuids(const uint8_t *candidates[],
- int max_candidates,
- enum storage_factory_security_class security_class);
+static int select_candidate_uuids(const struct rpc_uuid *candidates[], int max_candidates,
+ enum storage_factory_security_class security_class);
struct storage_backend *storage_factory_create(
enum storage_factory_security_class security_class)
{
- struct rpc_caller *storage_caller;
- uint16_t storage_sp_ids[1];
struct rot_store *new_backend = &backend_instance;
- const uint8_t *candidate_uuids[MAX_CANDIDATE_UUIDS];
- int num_candidate_uuids = select_candidate_uuids(candidate_uuids,
- MAX_CANDIDATE_UUIDS, security_class);
+ const struct rpc_uuid *candidate_uuids[MAX_CANDIDATE_UUIDS];
+ int num_candidate_uuids = select_candidate_uuids(candidate_uuids, MAX_CANDIDATE_UUIDS,
+ security_class);
struct storage_backend *result = NULL;
if (num_candidate_uuids && !new_backend->in_use) {
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
- storage_caller = ffarpc_caller_init(&new_backend->ffarpc_caller);
+ rpc_status = ts_rpc_caller_sp_init(&new_backend->caller);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
for (int i = 0; i < num_candidate_uuids; i++) {
-
- /* Try discovering candidate endpoints in preference order */
- if (ffarpc_caller_discover(candidate_uuids[i], storage_sp_ids,
- sizeof(storage_sp_ids)/sizeof(uint16_t))) {
-
- if (ffarpc_caller_open(&new_backend->ffarpc_caller, storage_sp_ids[0], 0) == 0) {
-
- result = secure_storage_client_init(&new_backend->secure_storage_client,
- storage_caller);
- }
-
+ rpc_status = rpc_caller_session_find_and_open(&new_backend->session,
+ &new_backend->caller,
+ candidate_uuids[i], 4096);
+
+ if (rpc_status == RPC_SUCCESS) {
+ result = secure_storage_client_init(
+ &new_backend->secure_storage_client,
+ &new_backend->session);
break;
}
}
- if (!result) {
-
- /* Failed to discover or open an RPC session with provider */
- ffarpc_caller_deinit(&new_backend->ffarpc_caller);
- }
-
new_backend->in_use = (result != NULL);
}
if (!result) {
+ ts_rpc_caller_sp_deinit(&new_backend->caller);
/**
* Errors during SP initialisation can be difficult to handle so
@@ -117,29 +110,25 @@ void storage_factory_destroy(struct storage_backend *backend)
if (backend) {
secure_storage_client_deinit(&backend_instance.secure_storage_client);
- ffarpc_caller_deinit(&backend_instance.ffarpc_caller);
+ rpc_caller_session_close(&backend_instance.session);
+ ts_rpc_caller_sp_deinit(&backend_instance.caller);
backend_instance.in_use = false;
}
}
-static int select_candidate_uuids(const uint8_t *candidates[],
- int max_candidates,
- enum storage_factory_security_class security_class)
+static int select_candidate_uuids(const struct rpc_uuid *candidates[], int max_candidates,
+ enum storage_factory_security_class security_class)
{
/* Runtime configuration not yet supported so fallback to using default UUIDs */
int num_candidates = 0;
if (max_candidates >= 2) {
-
if (security_class == storage_factory_security_class_INTERNAL_TRUSTED) {
-
- candidates[0] = default_internal_store_uuid;
- candidates[1] = default_protected_store_uuid;
- }
- else {
-
- candidates[0] = default_protected_store_uuid;
- candidates[1] = default_internal_store_uuid;
+ candidates[0] = &default_internal_store_uuid;
+ candidates[1] = &default_protected_store_uuid;
+ } else {
+ candidates[0] = &default_protected_store_uuid;
+ candidates[1] = &default_internal_store_uuid;
}
num_candidates = 2;
diff --git a/components/service/secure_storage/factory/sp/optee_trusted_store/component.cmake b/components/service/secure_storage/factory/sp/sfs_shared_block_store/component.cmake
index b06adb56a..82c25dd31 100644
--- a/components/service/secure_storage/factory/sp/optee_trusted_store/component.cmake
+++ b/components/service/secure_storage/factory/sp/sfs_shared_block_store/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
diff --git a/components/service/secure_storage/factory/sp/sfs_shared_block_store/storage_factory.c b/components/service/secure_storage/factory/sp/sfs_shared_block_store/storage_factory.c
new file mode 100644
index 000000000..36e606dc9
--- /dev/null
+++ b/components/service/secure_storage/factory/sp/sfs_shared_block_store/storage_factory.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/**
+ * A storage factory that creates storage backends that use the Secure Flash Store
+ * (SFS) with a shared block store residing in a separate SP. Selection of the
+ * storage partition to use for block storage is based on the requested security
+ * class.
+ */
+#include <stdbool.h>
+#include <stddef.h>
+#include "service/secure_storage/backend/secure_flash_store/secure_flash_store.h"
+#include "service/secure_storage/backend/secure_flash_store/flash/block_store_adapter/sfs_flash_block_store_adapter.h"
+#include "service/secure_storage/factory/storage_factory.h"
+#include "service/block_storage/block_store/block_store.h"
+#include "service/block_storage/factory/client/block_store_factory.h"
+#include "media/disk/guid.h"
+
+/* Overridable SFS configuration */
+
+/* Configures the minimum flash block size presented to SFS by the
+ * sfs_flash_block_store_adapter. SFS limits the maximum file size to
+ * the underlying block size. This configuration allows larger objects
+ * to be stored by aggregating multiple storage blocks and presenting
+ * them to SFS as a super block. */
+#ifndef CONFIG_SFS_MIN_FLASH_BLOCK_SIZE
+#define CONFIG_SFS_MIN_FLASH_BLOCK_SIZE (4096)
+#endif
+
+/* Configures the maximum number of objects held by SFS */
+#ifndef CONFIG_SFS_MAX_NUM_FILES
+#define CONFIG_SFS_MAX_NUM_FILES (10)
+#endif
+
+/* The storage backed specialization constructed by this factory */
+struct sfs_shared_block_store
+{
+ struct sfs_flash_block_store_adapter sfs_flash_adapter;
+ struct block_store *block_store;
+ bool in_use;
+};
+
+/* Only supports construction of a single instance */
+static struct sfs_shared_block_store storage_instance = { .in_use = false };
+
+struct storage_backend *storage_factory_create(
+ enum storage_factory_security_class security_class)
+{
+ struct storage_backend *storage_backend = NULL;
+
+ if (storage_instance.in_use)
+ return NULL;
+
+ /* Create client_block_store that uses shared storage provided by
+ * the block storage service provider */
+ storage_instance.block_store =
+ client_block_store_factory_create("sn:ffa:63646e80-eb52-462f-ac4f-8cdf3987519c:0");
+
+ if (storage_instance.block_store) {
+
+ struct uuid_octets guid;
+ const struct sfs_flash_info_t *flash_info = NULL;
+
+ if (security_class == storage_factory_security_class_INTERNAL_TRUSTED)
+ uuid_guid_octets_from_canonical(&guid, DISK_GUID_UNIQUE_PARTITION_PSA_ITS);
+ else
+ uuid_guid_octets_from_canonical(&guid, DISK_GUID_UNIQUE_PARTITION_PSA_PS);
+
+ psa_status_t status = sfs_flash_block_store_adapter_init(
+ &storage_instance.sfs_flash_adapter,
+ 0,
+ storage_instance.block_store,
+ &guid,
+ CONFIG_SFS_MIN_FLASH_BLOCK_SIZE,
+ CONFIG_SFS_MAX_NUM_FILES,
+ &flash_info);
+
+ if (status == PSA_SUCCESS) {
+
+ storage_backend = sfs_init(flash_info);
+ }
+
+ if ((status != PSA_SUCCESS) || !storage_backend) {
+
+ client_block_store_factory_destroy(storage_instance.block_store);
+ storage_instance.block_store = NULL;
+ }
+ }
+
+ storage_instance.in_use = (storage_instance.block_store != NULL);
+
+ return storage_backend;
+}
+
+void storage_factory_destroy(struct storage_backend *backend)
+{
+ if (backend && storage_instance.in_use) {
+
+ sfs_flash_block_store_adapter_deinit(
+ &storage_instance.sfs_flash_adapter);
+
+ client_block_store_factory_destroy(storage_instance.block_store);
+ storage_instance.block_store = NULL;
+
+ storage_instance.in_use = false;
+ }
+}
+
diff --git a/components/service/secure_storage/frontend/psa/its/test/its_api_tests.cpp b/components/service/secure_storage/frontend/psa/its/test/its_api_tests.cpp
index 53a6442a9..118a8de80 100644
--- a/components/service/secure_storage/frontend/psa/its/test/its_api_tests.cpp
+++ b/components/service/secure_storage/frontend/psa/its/test/its_api_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -55,7 +55,6 @@ void its_api_tests::storageLimitTest(size_t size_limit)
struct psa_storage_info_t storage_info;
static const size_t MAX_ITEM_SIZE = 10000;
uint8_t item[MAX_ITEM_SIZE];
- uint8_t read_item[MAX_ITEM_SIZE];
memset(item, 0x55, sizeof(item));
@@ -78,4 +77,4 @@ void its_api_tests::storageLimitTest(size_t size_limit)
/* Remove the item */
status = psa_its_remove(uid);
CHECK_EQUAL(PSA_SUCCESS, status);
-} \ No newline at end of file
+}
diff --git a/components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.cpp b/components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.cpp
index e4c2cb1ea..afb14ce42 100644
--- a/components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.cpp
+++ b/components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.cpp
@@ -12,7 +12,7 @@
* Creates a new slot and sets its contents in one go. Uses
* mandatory PS API operations only.
*/
-void ps_api_tests::createAndSet()
+void ps_api_tests::set()
{
psa_status_t status;
psa_storage_uid_t uid = 10;
@@ -27,10 +27,6 @@ void ps_api_tests::createAndSet()
status = psa_ps_get_info(uid, &storage_info);
CHECK_EQUAL(PSA_ERROR_DOES_NOT_EXIST, status);
- /* Create empty store record with capcity for the item */
- status = psa_ps_create(uid, sizeof(item), PSA_STORAGE_FLAG_NONE);
- CHECK_EQUAL(PSA_SUCCESS, status);
-
/* Store the item */
status = psa_ps_set(uid, sizeof(item), item, PSA_STORAGE_FLAG_NONE);
CHECK_EQUAL(PSA_SUCCESS, status);
@@ -69,6 +65,9 @@ void ps_api_tests::createAndSetExtended()
uint8_t item[ITEM_SIZE];
uint8_t read_item[ITEM_SIZE];
+ if ((psa_ps_get_support() & PSA_STORAGE_SUPPORT_SET_EXTENDED) == 0)
+ return;
+
memset(item, 0xaa, sizeof(item));
/* Probe to check item does not exist */
diff --git a/components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.h b/components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.h
index 1f107f608..6810fc306 100644
--- a/components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.h
+++ b/components/service/secure_storage/frontend/psa/ps/test/ps_api_tests.h
@@ -15,7 +15,7 @@ class ps_api_tests
{
public:
- static void createAndSet();
+ static void set();
static void createAndSetExtended();
};
diff --git a/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.c b/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.c
index 8703157a6..8278521f8 100644
--- a/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.c
+++ b/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.c
@@ -1,207 +1,178 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "secure_storage_provider.h"
-#include <protocols/service/secure_storage/packed-c/secure_storage_proto.h>
-#include <protocols/service/psa/packed-c/status.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <components/rpc/common/endpoint/rpc_interface.h>
+#include "components/common/utils/include/util.h"
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "protocols/service/secure_storage/packed-c/secure_storage_proto.h"
-
-static rpc_status_t set_handler(void *context, struct call_req *req)
+static rpc_status_t set_handler(void *context, struct rpc_request *req)
{
struct secure_storage_provider *this_context = (struct secure_storage_provider*)context;
- struct secure_storage_request_set *request_desc;
- psa_status_t psa_status;
+ struct secure_storage_request_set *request_desc = NULL;
+ size_t request_length = 0;
/* Checking if the descriptor fits into the request buffer */
- if (req->req_buf.data_len < sizeof(struct secure_storage_request_set))
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ if (req->request.data_length < sizeof(*request_desc))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
- request_desc = (struct secure_storage_request_set *)(req->req_buf.data);
+ request_desc = (struct secure_storage_request_set *)(req->request.data);
/* Checking for overflow */
- if (sizeof(struct secure_storage_request_set) + request_desc->data_length < request_desc->data_length)
- return TS_RPC_ERROR_INVALID_REQ_BODY;
-
- /* Checking if descriptor and data fits into the request buffer */
- if (req->req_buf.data_len < sizeof(struct secure_storage_request_set) + request_desc->data_length)
- return TS_RPC_ERROR_INVALID_REQ_BODY;
-
- psa_status = this_context->backend->interface->set(this_context->backend->context,
- req->caller_id,
- request_desc->uid,
- request_desc->data_length,
- request_desc->p_data,
- request_desc->create_flags);
- call_req_set_opstatus(req, psa_status);
-
- return TS_RPC_CALL_ACCEPTED;
+ if (ADD_OVERFLOW(sizeof(*request_desc), request_desc->data_length, &request_length))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+
+ /* Checking if the request descriptor and the data fits into the request buffer */
+ if (req->request.data_length < request_length)
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+
+ req->service_status = this_context->backend->interface->set(
+ this_context->backend->context, req->source_id, request_desc->uid,
+ request_desc->data_length, request_desc->p_data,
+ request_desc->create_flags);
+
+ return RPC_SUCCESS;
}
-static rpc_status_t get_handler(void *context, struct call_req *req)
+static rpc_status_t get_handler(void *context, struct rpc_request *req)
{
struct secure_storage_provider *this_context = (struct secure_storage_provider*)context;
- struct secure_storage_request_get *request_desc;
- psa_status_t psa_status;
+ struct secure_storage_request_get *request_desc = NULL;
- /* Checking if the descriptor fits into the request buffer */
- if (req->req_buf.data_len < sizeof(struct secure_storage_request_get))
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ /* Checking if the request descriptor fits into the request buffer */
+ if (req->request.data_length < sizeof(*request_desc))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
- request_desc = (struct secure_storage_request_get *)(req->req_buf.data);
+ request_desc = (struct secure_storage_request_get *)(req->request.data);
/* Clip the requested data size if it's too big for the response buffer */
- size_t data_size = (req->resp_buf.size < data_size) ?
- req->resp_buf.size :
- request_desc->data_size;
-
- psa_status = this_context->backend->interface->get(this_context->backend->context,
- req->caller_id, request_desc->uid,
- request_desc->data_offset,
- data_size,
- req->resp_buf.data, &req->resp_buf.data_len);
- call_req_set_opstatus(req, psa_status);
-
- return TS_RPC_CALL_ACCEPTED;
+ size_t data_size = MIN(req->response.size, request_desc->data_size);
+
+ req->service_status = this_context->backend->interface->get(
+ this_context->backend->context, req->source_id, request_desc->uid,
+ request_desc->data_offset, data_size,
+ req->response.data, &req->response.data_length);
+
+ return RPC_SUCCESS;
}
-static rpc_status_t get_info_handler(void *context, struct call_req *req)
+static rpc_status_t get_info_handler(void *context, struct rpc_request *req)
{
struct secure_storage_provider *this_context = (struct secure_storage_provider*)context;
- struct secure_storage_request_get_info *request_desc;
- struct secure_storage_response_get_info *response_desc;
- struct psa_storage_info_t storage_info;
- psa_status_t psa_status;
+ struct secure_storage_request_get_info *request_desc = NULL;
+ struct secure_storage_response_get_info *response_desc = NULL;
+ struct psa_storage_info_t storage_info = { 0 };
/* Checking if the descriptor fits into the request buffer */
- if (req->req_buf.data_len < sizeof(struct secure_storage_request_get_info))
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ if (req->request.data_length < sizeof(*request_desc))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
- request_desc = (struct secure_storage_request_get_info *)(req->req_buf.data);
+ request_desc = (struct secure_storage_request_get_info *)(req->request.data);
/* Checking if the response structure would fit the response buffer */
- if (req->resp_buf.size < sizeof(struct secure_storage_response_get_info))
- return TS_RPC_ERROR_INVALID_RESP_BODY;
+ if (req->response.size < sizeof(*response_desc))
+ return RPC_ERROR_INVALID_RESPONSE_BODY;
- response_desc = (struct secure_storage_response_get_info *)(req->resp_buf.data);
+ response_desc = (struct secure_storage_response_get_info *)(req->response.data);
- psa_status = this_context->backend->interface->get_info(this_context->backend->context,
- req->caller_id,
- request_desc->uid,
- &storage_info);
- call_req_set_opstatus(req, psa_status);
+ req->service_status = this_context->backend->interface->get_info(
+ this_context->backend->context, req->source_id, request_desc->uid, &storage_info);
- if (psa_status != PSA_SUCCESS) {
- req->resp_buf.data_len = 0;
- }
- else {
+ if (req->service_status == PSA_SUCCESS) {
response_desc->capacity = storage_info.capacity;
response_desc->size = storage_info.size;
response_desc->flags = storage_info.flags;
-
- req->resp_buf.data_len = sizeof(struct secure_storage_response_get_info);
+ req->response.data_length = sizeof(*response_desc);
}
- return TS_RPC_CALL_ACCEPTED;
+ return RPC_SUCCESS;
}
-static rpc_status_t remove_handler(void *context, struct call_req *req)
+static rpc_status_t remove_handler(void *context, struct rpc_request *req)
{
struct secure_storage_provider *this_context = (struct secure_storage_provider*)context;
- struct secure_storage_request_remove *request_desc;
- psa_status_t psa_status;
+ struct secure_storage_request_remove *request_desc = NULL;
/* Checking if the descriptor fits into the request buffer */
- if (req->req_buf.data_len < sizeof(struct secure_storage_request_remove))
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ if (req->request.data_length < sizeof(*request_desc))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
- request_desc = (struct secure_storage_request_remove *)(req->req_buf.data);
+ request_desc = (struct secure_storage_request_remove *)(req->request.data);
- psa_status = this_context->backend->interface->remove(this_context->backend->context,
- req->caller_id,
- request_desc->uid);
- call_req_set_opstatus(req, psa_status);
+ req->service_status = this_context->backend->interface->remove(
+ this_context->backend->context, req->source_id, request_desc->uid);
- return TS_RPC_CALL_ACCEPTED;
+ return RPC_SUCCESS;
}
-static rpc_status_t create_handler(void *context, struct call_req *req)
+static rpc_status_t create_handler(void *context, struct rpc_request *req)
{
struct secure_storage_provider *this_context = (struct secure_storage_provider*)context;
- struct secure_storage_request_create *request_desc;
- psa_status_t psa_status;
+ struct secure_storage_request_create *request_desc = NULL;
/* Checking if the descriptor fits into the request buffer */
- if (req->req_buf.data_len < sizeof(struct secure_storage_request_create))
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ if (req->request.data_length < sizeof(*request_desc))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
- request_desc = (struct secure_storage_request_create *)(req->req_buf.data);
+ request_desc = (struct secure_storage_request_create *)(req->request.data);
- psa_status = this_context->backend->interface->create(this_context->backend->context,
- req->caller_id,
- request_desc->uid,
- request_desc->capacity,
- request_desc->create_flags);
- call_req_set_opstatus(req, psa_status);
+ req->service_status = this_context->backend->interface->create(
+ this_context->backend->context, req->source_id, request_desc->uid,
+ request_desc->capacity, request_desc->create_flags);
- return TS_RPC_CALL_ACCEPTED;
+ return RPC_SUCCESS;
}
-static rpc_status_t set_extended_handler(void *context, struct call_req *req)
+static rpc_status_t set_extended_handler(void *context, struct rpc_request *req)
{
struct secure_storage_provider *this_context = (struct secure_storage_provider*)context;
- struct secure_storage_request_set_extended *request_desc;
- psa_status_t psa_status;
+ struct secure_storage_request_set_extended *request_desc = NULL;
+ size_t request_length = 0;
/* Checking if the descriptor fits into the request buffer */
- if (req->req_buf.data_len < sizeof(struct secure_storage_request_set_extended))
- return TS_RPC_ERROR_INVALID_REQ_BODY;
+ if (req->request.data_length < sizeof(*request_desc))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
- request_desc = (struct secure_storage_request_set_extended *)(req->req_buf.data);
+ request_desc = (struct secure_storage_request_set_extended *)(req->request.data);
/* Checking for overflow */
- if (sizeof(struct secure_storage_request_set_extended) + request_desc->data_length < request_desc->data_length)
- return TS_RPC_ERROR_INVALID_REQ_BODY;
-
- /* Checking if descriptor and data fits into the request buffer */
- if (req->req_buf.data_len < sizeof(struct secure_storage_request_set_extended) + request_desc->data_length)
- return TS_RPC_ERROR_INVALID_REQ_BODY;
-
- psa_status = this_context->backend->interface->set_extended(this_context->backend->context,
- req->caller_id,
- request_desc->uid,
- request_desc->data_offset,
- request_desc->data_length,
- request_desc->p_data);
- call_req_set_opstatus(req, psa_status);
-
- return TS_RPC_CALL_ACCEPTED;
+ if (ADD_OVERFLOW(sizeof(*request_desc), request_desc->data_length, &request_length))
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+
+ /* Checking if the request descriptor and the data fits into the request buffer */
+ if (req->request.data_length < request_length)
+ return RPC_ERROR_INVALID_REQUEST_BODY;
+
+ req->service_status = this_context->backend->interface->set_extended(
+ this_context->backend->context, req->source_id, request_desc->uid,
+ request_desc->data_offset, request_desc->data_length, request_desc->p_data);
+
+ return RPC_SUCCESS;
}
-static rpc_status_t get_support_handler(void *context, struct call_req *req)
+static rpc_status_t get_support_handler(void *context, struct rpc_request *req)
{
struct secure_storage_provider *this_context = (struct secure_storage_provider*)context;
- struct secure_storage_response_get_support *response_desc;
+ struct secure_storage_response_get_support *response_desc = NULL;
uint32_t feature_map;
/* Checking if the response structure would fit the response buffer */
- if (req->resp_buf.size < sizeof(struct secure_storage_response_get_support))
- return TS_RPC_ERROR_INVALID_RESP_BODY;
+ if (req->response.size < sizeof(struct secure_storage_response_get_support))
+ return RPC_ERROR_INVALID_RESPONSE_BODY;
- response_desc = (struct secure_storage_response_get_support *)(req->resp_buf.data);
+ response_desc = (struct secure_storage_response_get_support *)(req->response.data);
feature_map = this_context->backend->interface->get_support(this_context->backend->context,
- req->caller_id);
- call_req_set_opstatus(req, PSA_SUCCESS);
+ req->source_id);
+ req->service_status = PSA_SUCCESS;
response_desc->support = feature_map;
- req->resp_buf.data_len = sizeof(struct secure_storage_response_get_support);
+ req->response.data_length = sizeof(struct secure_storage_response_get_support);
- return TS_RPC_CALL_ACCEPTED;
+ return RPC_SUCCESS;
}
/* Handler mapping table for service */
@@ -215,25 +186,22 @@ static const struct service_handler handler_table[] = {
{TS_SECURE_STORAGE_OPCODE_GET_SUPPORT, get_support_handler}
};
-struct rpc_interface *secure_storage_provider_init(struct secure_storage_provider *context,
- struct storage_backend *backend)
+struct rpc_service_interface *secure_storage_provider_init(struct secure_storage_provider *context,
+ struct storage_backend *backend,
+ const struct rpc_uuid *service_uuid)
{
- struct rpc_interface *rpc_interface = NULL;
-
- if (context == NULL)
- goto out;
+ struct rpc_service_interface *rpc_interface = NULL;
- if (backend == NULL)
- goto out;
+ if (!context || !backend)
+ return NULL;
- service_provider_init(&context->base_provider, context, handler_table,
+ service_provider_init(&context->base_provider, context, service_uuid, handler_table,
sizeof(handler_table) / sizeof(handler_table[0]));
rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
context->backend = backend;
-out:
return rpc_interface;
}
diff --git a/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h b/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h
index 65e49da89..4b5f64311 100644
--- a/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h
+++ b/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h
@@ -7,8 +7,8 @@
#ifndef SECURE_STORAGE_PROVIDER_H
#define SECURE_STORAGE_PROVIDER_H
-#include <service/common/provider/service_provider.h>
-#include <service/secure_storage/backend/storage_backend.h>
+#include "service/common/provider/service_provider.h"
+#include "service/secure_storage/backend/storage_backend.h"
#ifdef __cplusplus
extern "C" {
@@ -25,8 +25,9 @@ struct secure_storage_provider {
struct storage_backend *backend;
};
-struct rpc_interface *secure_storage_provider_init(struct secure_storage_provider *context,
- struct storage_backend *backend);
+struct rpc_service_interface *secure_storage_provider_init(struct secure_storage_provider *context,
+ struct storage_backend *backend,
+ const struct rpc_uuid *service_uuid);
void secure_storage_provider_deinit(struct secure_storage_provider *context);
diff --git a/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h b/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h
new file mode 100644
index 000000000..ab2112c70
--- /dev/null
+++ b/components/service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SECURE_STORAGE_UUID_H
+#define SECURE_STORAGE_UUID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID \
+{ 0xdc, 0x1e, 0xef, 0x48, 0xb1, 0x7a, 0x4c, 0xcf, 0xac, 0x8b, 0xdf, 0xcf, 0xf7, 0x71, 0x1b, 0x14, }
+
+#define TS_PSA_PROTECTED_STORAGE_UUID \
+{ 0x75, 0x1b, 0xf8, 0x01, 0x3d, 0xde, 0x47, 0x68, 0xa5, 0x14, 0x0f, 0x10, 0xae, 0xed, 0x17, 0x90, }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECURE_STORAGE_UUID_H */
diff --git a/components/service/secure_storage/include/psa/storage_common.h b/components/service/secure_storage/include/psa/storage_common.h
index 4f6ba2a7d..317654594 100644
--- a/components/service/secure_storage/include/psa/storage_common.h
+++ b/components/service/secure_storage/include/psa/storage_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,8 +20,8 @@ typedef uint64_t psa_storage_uid_t;
typedef uint32_t psa_storage_create_flags_t;
struct psa_storage_info_t {
- size_t capacity;
- size_t size;
+ uint32_t capacity;
+ uint32_t size;
psa_storage_create_flags_t flags;
};
diff --git a/components/service/secure_storage/test/service/its_service_tests.cpp b/components/service/secure_storage/test/service/its_service_tests.cpp
index b976d613a..78c63af5e 100644
--- a/components/service/secure_storage/test/service/its_service_tests.cpp
+++ b/components/service/secure_storage/test/service/its_service_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,21 +20,18 @@ TEST_GROUP(ItsServiceTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_its_service_context = NULL;
service_locator_init();
- m_its_service_context = service_locator_query("sn:trustedfirmware.org:internal-trusted-storage:0", &status);
+ m_its_service_context = service_locator_query("sn:trustedfirmware.org:internal-trusted-storage:0");
CHECK(m_its_service_context);
- m_rpc_session_handle = service_context_open(m_its_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_its_service_context);
+ CHECK(m_rpc_session);
- struct storage_backend *storage_backend = secure_storage_client_init(&m_storage_client, caller);
+ struct storage_backend *storage_backend = secure_storage_client_init(&m_storage_client, m_rpc_session);
psa_its_frontend_init(storage_backend);
}
@@ -43,16 +40,20 @@ TEST_GROUP(ItsServiceTests)
{
psa_its_frontend_init(NULL);
- service_context_close(m_its_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_its_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_its_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_its_service_context);
- m_its_service_context = NULL;
+ service_context_relinquish(m_its_service_context);
+ m_its_service_context = NULL;
+ }
secure_storage_client_deinit(&m_storage_client);
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_its_service_context;
struct secure_storage_client m_storage_client;
};
@@ -60,4 +61,4 @@ TEST_GROUP(ItsServiceTests)
TEST(ItsServiceTests, storeNewItem)
{
its_api_tests::storeNewItem();
-}
+} \ No newline at end of file
diff --git a/components/service/secure_storage/test/service/ps_service_tests.cpp b/components/service/secure_storage/test/service/ps_service_tests.cpp
index fd19f08cc..d5cc5eff1 100644
--- a/components/service/secure_storage/test/service/ps_service_tests.cpp
+++ b/components/service/secure_storage/test/service/ps_service_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,21 +22,18 @@ TEST_GROUP(PsServiceTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_its_service_context = NULL;
service_locator_init();
- m_its_service_context = service_locator_query("sn:trustedfirmware.org:protected-storage:0", &status);
+ m_its_service_context = service_locator_query("sn:trustedfirmware.org:protected-storage:0");
CHECK(m_its_service_context);
- m_rpc_session_handle = service_context_open(m_its_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_its_service_context);
+ CHECK(m_rpc_session);
- struct storage_backend *storage_backend = secure_storage_client_init(&m_storage_client, caller);
+ struct storage_backend *storage_backend = secure_storage_client_init(&m_storage_client, m_rpc_session);
psa_ps_frontend_init(storage_backend);
psa_its_frontend_init(storage_backend);
@@ -47,16 +44,20 @@ TEST_GROUP(PsServiceTests)
psa_ps_frontend_init(NULL);
psa_its_frontend_init(NULL);
- service_context_close(m_its_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_its_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_its_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_its_service_context);
- m_its_service_context = NULL;
+ service_context_relinquish(m_its_service_context);
+ m_its_service_context = NULL;
+ }
secure_storage_client_deinit(&m_storage_client);
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_its_service_context;
struct secure_storage_client m_storage_client;
};
@@ -68,10 +69,10 @@ TEST(PsServiceTests, storeNewItem)
TEST(PsServiceTests, createAndSet)
{
- ps_api_tests::createAndSet();
+ ps_api_tests::set();
}
TEST(PsServiceTests, createAndSetExtended)
{
ps_api_tests::createAndSetExtended();
-}
+} \ No newline at end of file
diff --git a/components/service/smm_variable/backend/test/variable_store_tests.cpp b/components/service/smm_variable/backend/test/variable_store_tests.cpp
deleted file mode 100644
index f6aba13a4..000000000
--- a/components/service/smm_variable/backend/test/variable_store_tests.cpp
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <string>
-#include <vector>
-#include <string.h>
-#include <CppUTest/TestHarness.h>
-#include <service/smm_variable/backend/uefi_variable_store.h>
-#include <service/secure_storage/backend/mock_store/mock_store.h>
-
-TEST_GROUP(UefiVariableStoreTests)
-{
- void setup()
- {
- m_persistent_backend = mock_store_init(&m_persistent_store);
- m_volatile_backend = mock_store_init(&m_volatile_store);
-
- efi_status_t status = uefi_variable_store_init(
- &m_uefi_variable_store,
- OWNER_ID,
- MAX_VARIABLES,
- m_persistent_backend,
- m_volatile_backend);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- setup_common_guid();
- }
-
- void teardown()
- {
- uefi_variable_store_deinit(&m_uefi_variable_store);
- }
-
- void setup_common_guid()
- {
- m_common_guid.Data1 = 0x12341234;
- m_common_guid.Data2 = 0x1234;
- m_common_guid.Data3 = 0x1234;
- m_common_guid.Data4[0] = 0x00;
- m_common_guid.Data4[1] = 0x01;
- m_common_guid.Data4[2] = 0x02;
- m_common_guid.Data4[3] = 0x03;
- m_common_guid.Data4[4] = 0x04;
- m_common_guid.Data4[5] = 0x05;
- m_common_guid.Data4[6] = 0x06;
- m_common_guid.Data4[7] = 0x07;
- }
-
- std::vector<int16_t> to_variable_name(const std::wstring &string)
- {
- std::vector<int16_t> var_name;
-
- for (size_t i = 0; i < string.size(); i++) {
-
- var_name.push_back((int16_t)string[i]);
- }
-
- /* Add mandatory null terminator */
- var_name.push_back(0);
-
- return var_name;
- }
-
- bool compare_variable_name(
- const std::wstring &expected,
- const int16_t *name,
- size_t name_size) {
-
- bool is_equal = (expected.size() + 1 <= name_size / sizeof(int16_t));
-
- for (size_t i = 0; is_equal && i < expected.size(); i++) {
-
- if (name[i] != (int16_t)expected[i]) {
-
- is_equal = false;
- break;
- }
- }
-
- return is_equal;
- }
-
- efi_status_t set_variable(
- const std::wstring &name,
- const std::string &data,
- uint32_t attributes)
- {
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
- size_t data_size = data.size();
- uint8_t msg_buffer[SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, data_size)];
-
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_variable =
- (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)msg_buffer;
-
- access_variable->Guid = m_common_guid;
- access_variable->Attributes = attributes;
-
- access_variable->NameSize = name_size;
- memcpy(access_variable->Name, var_name.data(), name_size);
-
- access_variable->DataSize = data_size;
- memcpy(&msg_buffer[SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_variable)],
- data.c_str(), data_size);
-
- efi_status_t status = uefi_variable_store_set_variable(
- &m_uefi_variable_store,
- access_variable);
-
- return status;
- }
-
- efi_status_t get_variable(
- const std::wstring &name,
- std::string &data)
- {
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
- size_t total_size = 0;
- uint8_t msg_buffer[VARIABLE_BUFFER_SIZE];
-
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_variable =
- (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)msg_buffer;
-
- access_variable->Guid = m_common_guid;
- access_variable->Attributes = 0;
-
- access_variable->NameSize = name_size;
- memcpy(access_variable->Name, var_name.data(), name_size);
-
- access_variable->DataSize = 0;
-
- efi_status_t status = uefi_variable_store_get_variable(
- &m_uefi_variable_store,
- access_variable,
- VARIABLE_BUFFER_SIZE -
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_variable),
- &total_size);
-
- if (status == EFI_SUCCESS) {
-
- const char *data_start = (const char*)(msg_buffer +
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_variable));
-
- data = std::string(data_start, access_variable->DataSize);
- }
-
- return status;
- }
-
- efi_status_t set_check_var_property(
- const std::wstring &name,
- const VAR_CHECK_VARIABLE_PROPERTY &check_property)
- {
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
- uint8_t msg_buffer[SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size)];
-
- SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *check_var =
- (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY*)msg_buffer;
-
- check_var->Guid = m_common_guid;
- check_var->NameSize = name_size;
- memcpy(check_var->Name, var_name.data(), name_size);
-
- check_var->VariableProperty = check_property;
-
- efi_status_t status = uefi_variable_store_set_var_check_property(
- &m_uefi_variable_store,
- check_var);
-
- return status;
- }
-
- void zap_stored_variable(
- const std::wstring &name)
- {
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
-
- /* Create the condition where a variable is indexed but
- * there is no corresponding stored object.
- */
- struct variable_index *variable_index = &m_uefi_variable_store.variable_index;
-
- const struct variable_info *info = variable_index_find(
- variable_index,
- &m_common_guid,
- name_size,
- var_name.data());
-
- if (info && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
-
- struct storage_backend *storage_backend = m_uefi_variable_store.persistent_store;
-
- storage_backend->interface->remove(
- storage_backend->context,
- OWNER_ID,
- info->metadata.uid);
- }
- }
-
- void power_cycle()
- {
- /* Simulate a power-cycle */
- uefi_variable_store_deinit(&m_uefi_variable_store);
-
- /* Lose volatile store contents */
- mock_store_reset(&m_volatile_store);
-
- efi_status_t status = uefi_variable_store_init(
- &m_uefi_variable_store,
- OWNER_ID,
- MAX_VARIABLES,
- m_persistent_backend,
- m_volatile_backend);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- }
-
- static const size_t MAX_VARIABLES = 10;
- static const uint32_t OWNER_ID = 100;
- static const size_t VARIABLE_BUFFER_SIZE = 1024;
-
- struct uefi_variable_store m_uefi_variable_store;
- struct mock_store m_persistent_store;
- struct mock_store m_volatile_store;
- struct storage_backend *m_persistent_backend;
- struct storage_backend *m_volatile_backend;
- EFI_GUID m_common_guid;
-};
-
-TEST(UefiVariableStoreTests, setGetRoundtrip)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
- std::string input_data = "quick brown fox";
- std::string output_data;
-
- status = set_variable(var_name, input_data, 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Expect got variable data to be the same as the set value */
- UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
- LONGS_EQUAL(0, input_data.compare(output_data));
-}
-
-TEST(UefiVariableStoreTests, persistentSetGet)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
- std::string input_data = "quick brown fox";
- std::string output_data;
-
- status = set_variable(var_name, input_data, EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Expect got variable data to be the same as the set value */
- UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
- LONGS_EQUAL(0, input_data.compare(output_data));
-
- /* Expect the variable to survive a power cycle */
- power_cycle();
-
- output_data = std::string();
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Still expect got variable data to be the same as the set value */
- UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
- LONGS_EQUAL(0, input_data.compare(output_data));
-}
-
-TEST(UefiVariableStoreTests, removeVolatile)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name = L"rm_volatile_variable";
- std::string input_data = "quick brown fox";
- std::string output_data;
-
- status = set_variable(var_name, input_data, 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Remove by setting with zero data length */
- status = set_variable(var_name, std::string(), 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Expect variable to no loger exist */
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
-}
-
-TEST(UefiVariableStoreTests, removePersistent)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name = L"rm_nv_variable";
- std::string input_data = "quick brown fox";
- std::string output_data;
-
- status = set_variable(var_name, input_data, EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Remove by setting with zero data length */
- status = set_variable(var_name, std::string(), 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Expect variable to no loger exist */
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
-}
-
-TEST(UefiVariableStoreTests, bootServiceAccess)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
- std::string input_data = "a variable with access restricted to boot";
- std::string output_data;
-
- status = set_variable(
- var_name,
- input_data,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* 'Reboot' */
- power_cycle();
-
- /* Expect access to be permitted */
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
- LONGS_EQUAL(0, input_data.compare(output_data));
-
- /* End of boot phase */
- status = uefi_variable_store_exit_boot_service(&m_uefi_variable_store);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Expect access to be blocked */
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_ACCESS_DENIED, status);
-}
-
-TEST(UefiVariableStoreTests, runtimeAccess)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
- std::string input_data = "a variable with access restricted to runtime";
- std::string output_data;
-
- status = set_variable(
- var_name,
- input_data,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* 'Reboot' */
- power_cycle();
-
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_ACCESS_DENIED, status);
-
- /* End of boot phase */
- status = uefi_variable_store_exit_boot_service(&m_uefi_variable_store);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Expect access to be permitted */
- status = get_variable(var_name, output_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
- LONGS_EQUAL(0, input_data.compare(output_data));
-}
-
-TEST(UefiVariableStoreTests, enumerateStoreContents)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name_1 = L"test_variable_1";
- std::wstring var_name_2 = L"test_variable_2";
- std::wstring var_name_3 = L"test_variable_3";
- std::string input_data = "blah blah";
-
- /* Add some variables - a mixture of NV and volatile */
- status = set_variable(
- var_name_1,
- input_data,
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- status = set_variable(
- var_name_2,
- input_data,
- 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- status = set_variable(
- var_name_3,
- input_data,
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Prepare to enumerate */
- uint8_t msg_buffer[VARIABLE_BUFFER_SIZE];
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *next_name =
- (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)msg_buffer;
- size_t max_name_len = VARIABLE_BUFFER_SIZE -
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
-
- /* Enumerate store contents */
- size_t total_len = 0;
- next_name->NameSize = sizeof(int16_t);
- next_name->Name[0] = 0;
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- CHECK_TRUE(compare_variable_name(var_name_1, next_name->Name, next_name->NameSize));
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- CHECK_TRUE(compare_variable_name(var_name_2, next_name->Name, next_name->NameSize));
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- CHECK_TRUE(compare_variable_name(var_name_3, next_name->Name, next_name->NameSize));
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
-
- power_cycle();
-
- /* Enumerate again - should be left with just NV variables.
- * Use a different but equally valid null name.
- */
- next_name->NameSize = 10 * sizeof(int16_t);
- memset(next_name->Name, 0, next_name->NameSize);
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- CHECK_TRUE(compare_variable_name(var_name_1, next_name->Name, next_name->NameSize));
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- CHECK_TRUE(compare_variable_name(var_name_3, next_name->Name, next_name->NameSize));
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
-}
-
-TEST(UefiVariableStoreTests, failedNvSet)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name_1 = L"test_variable_1";
- std::wstring var_name_2 = L"test_variable_2";
- std::wstring var_name_3 = L"test_variable_3";
- std::string input_data = "blah blah";
-
- /* Add some variables - a mixture of NV and volatile */
- status = set_variable(
- var_name_1,
- input_data,
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- status = set_variable(
- var_name_2,
- input_data,
- 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- status = set_variable(
- var_name_3,
- input_data,
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Simulate a power failure which resulted in the
- * variable index being written but not the corresponding
- * data.
- */
- zap_stored_variable(var_name_3);
- power_cycle();
-
- /* After the power cycle, we expect the volatile variable
- * to have gone and for the index to have been cleaned up
- * for the failed variable 3.
- */
- uint8_t msg_buffer[VARIABLE_BUFFER_SIZE];
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *next_name =
- (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)msg_buffer;
- size_t max_name_len = VARIABLE_BUFFER_SIZE -
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
-
- /* Enumerate store contents */
- size_t total_len = 0;
- next_name->NameSize = sizeof(int16_t);
- next_name->Name[0] = 0;
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
- CHECK_TRUE(compare_variable_name(var_name_1, next_name->Name, next_name->NameSize));
-
- status = uefi_variable_store_get_next_variable_name(
- &m_uefi_variable_store,
- next_name,
- max_name_len,
- &total_len);
- UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
-}
-
-TEST(UefiVariableStoreTests, unsupportedAttribute)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name_1 = L"test_variable_1";
- std::string input_data = "blah blah";
-
- /* Add a variable with an unsupported attribute */
- status = set_variable(
- var_name_1,
- input_data,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS);
- UNSIGNED_LONGLONGS_EQUAL(EFI_UNSUPPORTED, status);
-}
-
-TEST(UefiVariableStoreTests, readOnlycheck)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name_1 = L"test_variable_1";
- std::string input_data = "blah blah";
-
- /* Add a variable */
- status = set_variable(
- var_name_1,
- input_data,
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Apply a check to constrain to Read Only */
- VAR_CHECK_VARIABLE_PROPERTY check_property;
- check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
- check_property.Attributes = 0;
- check_property.Property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
- check_property.MinSize = 0;
- check_property.MaxSize = 100;
-
- status = set_check_var_property(var_name_1, check_property);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Subsequent set operations should fail */
- status = set_variable(
- var_name_1,
- input_data,
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_WRITE_PROTECTED, status);
-}
-
-TEST(UefiVariableStoreTests, noRemoveCheck)
-{
- efi_status_t status = EFI_SUCCESS;
- std::wstring var_name_1 = L"test_variable_1";
- std::string input_data = "blah blah";
-
- /* Add a variable */
- status = set_variable(
- var_name_1,
- input_data,
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Apply a check to constrain size to > 0. This should prevent removal */
- VAR_CHECK_VARIABLE_PROPERTY check_property;
- check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
- check_property.Attributes = 0;
- check_property.Property = 0;
- check_property.MinSize = 1;
- check_property.MaxSize = 10;
-
- status = set_check_var_property(var_name_1, check_property);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* Try and remove by setting with zero length data */
- status = set_variable(
- var_name_1,
- std::string(),
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, status);
-
- /* Setting with non zero data should work */
- status = set_variable(
- var_name_1,
- std::string("Good"),
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
-
- /* But with data that exceeds the MaxSize */
- status = set_variable(
- var_name_1,
- std::string("A data value that exceeds the MaxSize"),
- EFI_VARIABLE_NON_VOLATILE);
- UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, status);
-}
diff --git a/components/service/smm_variable/backend/uefi_variable_store.c b/components/service/smm_variable/backend/uefi_variable_store.c
deleted file mode 100644
index b7091d75b..000000000
--- a/components/service/smm_variable/backend/uefi_variable_store.c
+++ /dev/null
@@ -1,697 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include "uefi_variable_store.h"
-#include "variable_index_iterator.h"
-#include "variable_checker.h"
-
-/* Private functions */
-static void load_variable_index(
- struct uefi_variable_store *context);
-
-static efi_status_t sync_variable_index(
- struct uefi_variable_store *context);
-
-static efi_status_t check_capabilities(
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
-
-static efi_status_t check_access_permitted(
- const struct uefi_variable_store *context,
- const struct variable_info *info);
-
-static efi_status_t check_access_permitted_on_set(
- const struct uefi_variable_store *context,
- const struct variable_info *info,
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
-
-static efi_status_t store_variable_data(
- struct uefi_variable_store *context,
- const struct variable_info *info,
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
-
-static efi_status_t remove_variable_data(
- struct uefi_variable_store *context,
- const struct variable_info *info);
-
-static efi_status_t load_variable_data(
- struct uefi_variable_store *context,
- const struct variable_info *info,
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
- size_t max_data_len);
-
-static void purge_orphan_index_entries(
- struct uefi_variable_store *context);
-
-static efi_status_t psa_to_efi_storage_status(
- psa_status_t psa_status);
-
-static efi_status_t check_name_terminator(
- const int16_t *name,
- size_t name_size);
-
-/* Private UID for storing the variable index */
-#define VARIABLE_INDEX_STORAGE_UID (1)
-
-
-efi_status_t uefi_variable_store_init(
- struct uefi_variable_store *context,
- uint32_t owner_id,
- size_t max_variables,
- struct storage_backend *persistent_store,
- struct storage_backend *volatile_store)
-{
- efi_status_t status = EFI_SUCCESS;
-
- context->persistent_store = persistent_store;
- context->volatile_store = volatile_store;
-
- context->owner_id = owner_id;
- context->is_boot_service = true;
-
- status = variable_index_init(&context->variable_index, max_variables);
-
- if (status == EFI_SUCCESS) {
-
- /* Allocate a buffer for synchronizing the variable index with the persistent store */
- context->index_sync_buffer_size = variable_index_max_dump_size(&context->variable_index);
- context->index_sync_buffer = NULL;
-
- if (context->index_sync_buffer_size) {
-
- context->index_sync_buffer = malloc(context->index_sync_buffer_size);
- status = (context->index_sync_buffer) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
- }
-
- /* Load the variable index with NV variable info from the persistent store */
- if (context->index_sync_buffer) {
-
- load_variable_index(context);
- purge_orphan_index_entries(context);
- }
- }
-
- return status;
-}
-
-void uefi_variable_store_deinit(
- struct uefi_variable_store *context)
-{
- variable_index_deinit(&context->variable_index);
-
- free(context->index_sync_buffer);
- context->index_sync_buffer = NULL;
-}
-
-efi_status_t uefi_variable_store_set_variable(
- struct uefi_variable_store *context,
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
-{
- efi_status_t status = check_name_terminator(var->Name, var->NameSize);
- if (status != EFI_SUCCESS) return status;
-
- status = check_capabilities(var);
- bool should_sync_index = false;
-
- if (status != EFI_SUCCESS) return status;
-
- /* Find in index */
- const struct variable_info *info = variable_index_find(
- &context->variable_index,
- &var->Guid,
- var->NameSize,
- var->Name);
-
- if (info) {
-
- /* Variable info already exists */
- status = check_access_permitted_on_set(context, info, var);
-
- if (status == EFI_SUCCESS) {
-
- should_sync_index =
- (var->Attributes & EFI_VARIABLE_NON_VOLATILE) ||
- (info->is_variable_set && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE));
-
- if (var->DataSize) {
-
- /* It's a set rather than a remove operation */
- variable_index_update_variable(
- info,
- var->Attributes);
- }
- else {
-
- /* It's a remove operation - for a remove, the variable
- * data must be removed from the storage backend before
- * modifying and syncing the variable index. This ensures
- * that it's never possible for an object to exist within
- * the storage backend without a corresponding index entry.
- */
- remove_variable_data(context, info);
- variable_index_remove_variable(&context->variable_index, info);
-
- /* Variable info no longer valid */
- info = NULL;
- }
- }
- else {
-
- /* Access forbidden */
- info = NULL;
- }
- }
- else if (var->DataSize) {
-
- /* It's a new variable */
- info = variable_index_add_variable(
- &context->variable_index,
- &var->Guid,
- var->NameSize,
- var->Name,
- var->Attributes);
-
- if (!info) status = EFI_OUT_OF_RESOURCES;
- should_sync_index = info && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
- }
-
- /* The order of these operations is important. For an update
- * or create operation, The variable index is always synchronized
- * to NV storage first, then the variable data is stored. If the
- * data store operation fails or doesn't happen due to a power failure,
- * the inconistency between the variable index and the persistent
- * store is detectable and may be corrected by purging the corresponding
- * index entry.
- */
- if (should_sync_index) {
-
- status = sync_variable_index(context);
- }
-
- /* Store any variable data to the storage backend */
- if (info && (status == EFI_SUCCESS)) {
-
- status = store_variable_data(context, info, var);
- }
-
- return status;
-}
-
-efi_status_t uefi_variable_store_get_variable(
- struct uefi_variable_store *context,
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
- size_t max_data_len,
- size_t *total_length)
-{
- efi_status_t status = check_name_terminator(var->Name, var->NameSize);
- if (status != EFI_SUCCESS) return status;
-
- status = EFI_NOT_FOUND;
- *total_length = 0;
-
- const struct variable_info *info = variable_index_find(
- &context->variable_index,
- &var->Guid,
- var->NameSize,
- var->Name);
-
- if (info && info->is_variable_set) {
-
- /* Variable already exists */
- status = check_access_permitted(context, info);
-
- if (status == EFI_SUCCESS) {
-
- status = load_variable_data(context, info, var, max_data_len);
- var->Attributes = info->metadata.attributes;
- *total_length = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_TOTAL_SIZE(var);
- }
- }
-
- return status;
-}
-
-efi_status_t uefi_variable_store_get_next_variable_name(
- struct uefi_variable_store *context,
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *cur,
- size_t max_name_len,
- size_t *total_length)
-{
- efi_status_t status = check_name_terminator(cur->Name, cur->NameSize);
- if (status != EFI_SUCCESS) return status;
-
- status = EFI_NOT_FOUND;
- *total_length = 0;
-
- const struct variable_info *info = variable_index_find_next(
- &context->variable_index,
- &cur->Guid,
- cur->NameSize,
- cur->Name);
-
- if (info && (info->metadata.name_size <= max_name_len)) {
-
- cur->Guid = info->metadata.guid;
- cur->NameSize = info->metadata.name_size;
- memcpy(cur->Name, info->metadata.name, info->metadata.name_size);
-
- *total_length = SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_TOTAL_SIZE(cur);
-
- status = EFI_SUCCESS;
- }
-
- return status;
-}
-
-efi_status_t uefi_variable_store_query_variable_info(
- struct uefi_variable_store *context,
- SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *cur)
-{
- efi_status_t status = EFI_UNSUPPORTED;
-
-
- return status;
-}
-
-efi_status_t uefi_variable_store_exit_boot_service(
- struct uefi_variable_store *context)
-{
- context->is_boot_service = false;
- return EFI_SUCCESS;
-}
-
-efi_status_t uefi_variable_store_set_var_check_property(
- struct uefi_variable_store *context,
- const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *property)
-{
- efi_status_t status = check_name_terminator(property->Name, property->NameSize);
- if (status != EFI_SUCCESS) return status;
-
- /* Find in index */
- const struct variable_info *info = variable_index_find(
- &context->variable_index,
- &property->Guid,
- property->NameSize,
- property->Name);
-
- if (info) {
-
- /* Applying check constraints to an existing variable that may have
- * constraints already set. These could constrain the setting of
- * the constraints.
- */
- struct variable_constraints constraints = info->check_constraints;
-
- status = variable_checker_set_constraints(
- &constraints,
- info->is_constraints_set,
- &property->VariableProperty);
-
- if (status == EFI_SUCCESS) {
-
- variable_index_update_constraints(info, &constraints);
- }
- }
- else {
-
- /* Applying check constraints for a new variable */
- struct variable_constraints constraints;
-
- status = variable_checker_set_constraints(
- &constraints,
- false,
- &property->VariableProperty);
-
- if (status == EFI_SUCCESS) {
-
- info = variable_index_add_constraints(
- &context->variable_index,
- &property->Guid,
- property->NameSize,
- property->Name,
- &constraints);
-
- if (!info) status = EFI_OUT_OF_RESOURCES;
- }
- }
-
- return status;
-}
-
-efi_status_t uefi_variable_store_get_var_check_property(
- struct uefi_variable_store *context,
- SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *property)
-{
- efi_status_t status = check_name_terminator(property->Name, property->NameSize);
- if (status != EFI_SUCCESS) return status;
-
- status = EFI_NOT_FOUND;
-
- const struct variable_info *info = variable_index_find(
- &context->variable_index,
- &property->Guid,
- property->NameSize,
- property->Name);
-
- if (info && info->is_constraints_set) {
-
- variable_checker_get_constraints(
- &info->check_constraints,
- &property->VariableProperty);
-
- status = EFI_SUCCESS;
- }
-
- return status;
-}
-
-static void load_variable_index(
- struct uefi_variable_store *context)
-{
- struct storage_backend *persistent_store = context->persistent_store;
-
- if (persistent_store) {
-
- size_t data_len = 0;
-
- psa_status_t psa_status = persistent_store->interface->get(
- persistent_store->context,
- context->owner_id,
- VARIABLE_INDEX_STORAGE_UID,
- 0,
- context->index_sync_buffer_size,
- context->index_sync_buffer,
- &data_len);
-
- if (psa_status == PSA_SUCCESS) {
-
- variable_index_restore(&context->variable_index, data_len, context->index_sync_buffer);
- }
- }
-}
-
-static efi_status_t sync_variable_index(
- struct uefi_variable_store *context)
-{
- efi_status_t status = EFI_SUCCESS;
-
- /* Sync the varibale index to storage if anything is dirty */
- size_t data_len = 0;
-
- bool is_dirty = variable_index_dump(
- &context->variable_index,
- context->index_sync_buffer_size,
- context->index_sync_buffer,
- &data_len);
-
- if (is_dirty) {
-
- struct storage_backend *persistent_store = context->persistent_store;
-
- if (persistent_store) {
-
- psa_status_t psa_status = persistent_store->interface->set(
- persistent_store->context,
- context->owner_id,
- VARIABLE_INDEX_STORAGE_UID,
- data_len,
- context->index_sync_buffer,
- PSA_STORAGE_FLAG_NONE);
-
- status = psa_to_efi_storage_status(psa_status);
- }
- }
-
- return status;
-}
-
-static efi_status_t check_capabilities(
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
-{
- efi_status_t status = EFI_SUCCESS;
-
- /* Check if any unsupported variable attributes have been requested */
- if (var->Attributes & ~(
- EFI_VARIABLE_NON_VOLATILE |
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS)) {
-
- /* An unsupported attribute has been requested */
- status = EFI_UNSUPPORTED;
- }
-
- return status;
-}
-
-static efi_status_t check_access_permitted(
- const struct uefi_variable_store *context,
- const struct variable_info *info)
-{
- efi_status_t status = EFI_SUCCESS;
-
- if (info->is_variable_set) {
-
- if (info->metadata.attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) {
-
- if (!context->is_boot_service) status = EFI_ACCESS_DENIED;
- }
- else if (info->metadata.attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
-
- if (context->is_boot_service) status = EFI_ACCESS_DENIED;
- }
- }
-
- return status;
-}
-
-static efi_status_t check_access_permitted_on_set(
- const struct uefi_variable_store *context,
- const struct variable_info *info,
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
-{
- efi_status_t status = check_access_permitted(context, info);
-
- if ((status == EFI_SUCCESS) && info->is_constraints_set) {
-
- /* Apply check constraints */
- status = variable_checker_check_on_set(
- &info->check_constraints,
- var->Attributes,
- var->DataSize);
- }
-
- if ((status == EFI_SUCCESS) && var->DataSize) {
-
- /* Restrict which attributes can be modified for an existing variable */
- if ((var->Attributes & EFI_VARIABLE_NON_VOLATILE) !=
- (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
-
- /* Don't permit change of storage class */
- status = EFI_INVALID_PARAMETER;
- }
- }
-
- return status;
-}
-
-static efi_status_t store_variable_data(
- struct uefi_variable_store *context,
- const struct variable_info *info,
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
-{
- psa_status_t psa_status = PSA_SUCCESS;
- size_t data_len = var->DataSize;
- const uint8_t *data = (const uint8_t*)var +
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
-
- bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
-
- struct storage_backend *storage_backend = (is_nv) ?
- context->persistent_store :
- context->volatile_store;
-
- if (storage_backend) {
-
- psa_status = storage_backend->interface->set(
- storage_backend->context,
- context->owner_id,
- info->metadata.uid,
- data_len,
- data,
- PSA_STORAGE_FLAG_NONE);
- }
-
- if ((psa_status != PSA_SUCCESS) && is_nv) {
-
- /* A storage failure has occurred so attempt to fix any
- * mismatch between the variable index and stored NV variables.
- */
- purge_orphan_index_entries(context);
- }
-
- return psa_to_efi_storage_status(psa_status);
-}
-
-static efi_status_t remove_variable_data(
- struct uefi_variable_store *context,
- const struct variable_info *info)
-{
- psa_status_t psa_status = PSA_SUCCESS;
-
- if (info->is_variable_set) {
-
- bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
-
- struct storage_backend *storage_backend = (is_nv) ?
- context->persistent_store :
- context->volatile_store;
-
- if (storage_backend) {
-
- psa_status = storage_backend->interface->remove(
- storage_backend->context,
- context->owner_id,
- info->metadata.uid);
- }
- }
-
- return psa_to_efi_storage_status(psa_status);
-}
-
-static efi_status_t load_variable_data(
- struct uefi_variable_store *context,
- const struct variable_info *info,
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
- size_t max_data_len)
-{
- psa_status_t psa_status = PSA_SUCCESS;
- size_t data_len = 0;
- uint8_t *data = (uint8_t*)var +
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
-
- bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
-
- struct storage_backend *storage_backend = (is_nv) ?
- context->persistent_store :
- context->volatile_store;
-
- if (storage_backend) {
-
- psa_status = storage_backend->interface->get(
- storage_backend->context,
- context->owner_id,
- info->metadata.uid,
- 0,
- max_data_len,
- data,
- &data_len);
-
- var->DataSize = data_len;
- }
-
- return psa_to_efi_storage_status(psa_status);
-}
-
-static void purge_orphan_index_entries(
- struct uefi_variable_store *context)
-{
- bool any_orphans = false;
- struct variable_index_iterator iter;
- variable_index_iterator_first(&iter, &context->variable_index);
-
- /* Iterate over variable index looking for any entries for NV
- * variables where there is no corresponding object in the
- * persistent store. This condition could arise due to
- * a power failure before an object is stored.
- */
- while (!variable_index_iterator_is_done(&iter)) {
-
- const struct variable_info *info = variable_index_iterator_current(&iter);
-
- if (info->is_variable_set && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
-
- struct psa_storage_info_t storage_info;
- struct storage_backend *storage_backend = context->persistent_store;
-
- psa_status_t psa_status = storage_backend->interface->get_info(
- storage_backend->context,
- context->owner_id,
- info->metadata.uid,
- &storage_info);
-
- if (psa_status != PSA_SUCCESS) {
-
- /* Detected a mismatch between the index and storage */
- variable_index_remove_variable(&context->variable_index, info);
- any_orphans = true;
- }
- }
-
- variable_index_iterator_next(&iter);
- }
-
- if (any_orphans) sync_variable_index(context);
-}
-
-static efi_status_t psa_to_efi_storage_status(
- psa_status_t psa_status)
-{
- efi_status_t efi_status = EFI_DEVICE_ERROR;
-
- switch(psa_status)
- {
- case PSA_SUCCESS:
- efi_status = EFI_SUCCESS;
- break;
- case PSA_ERROR_NOT_PERMITTED:
- efi_status = EFI_ACCESS_DENIED;
- break;
- case PSA_ERROR_INVALID_ARGUMENT:
- efi_status = EFI_INVALID_PARAMETER;
- break;
- case PSA_ERROR_BAD_STATE:
- efi_status = EFI_NOT_READY;
- break;
- case PSA_ERROR_BUFFER_TOO_SMALL:
- efi_status = EFI_BUFFER_TOO_SMALL;
- break;
- case PSA_ERROR_DOES_NOT_EXIST:
- efi_status = EFI_NOT_FOUND;
- break;
- case PSA_ERROR_INSUFFICIENT_MEMORY:
- efi_status = EFI_OUT_OF_RESOURCES;
- break;
- case PSA_ERROR_INSUFFICIENT_STORAGE:
- efi_status = EFI_OUT_OF_RESOURCES;
- break;
- case PSA_ERROR_STORAGE_FAILURE:
- efi_status = EFI_DEVICE_ERROR;
- break;
- case PSA_STATUS_HARDWARE_FAILURE:
- efi_status = EFI_DEVICE_ERROR;
- break;
- default:
- break;
- }
-
- return efi_status;
-}
-
-static efi_status_t check_name_terminator(
- const int16_t *name,
- size_t name_size)
-{
- /* Variable names must be null terminated */
- if (name_size < sizeof(int16_t) || name[name_size/sizeof (int16_t) - 1] != L'\0') {
-
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_SUCCESS;
-}
diff --git a/components/service/smm_variable/backend/variable_index.c b/components/service/smm_variable/backend/variable_index.c
deleted file mode 100644
index 99d7c97a8..000000000
--- a/components/service/smm_variable/backend/variable_index.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include "variable_index.h"
-
-/* Private functions */
-static uint64_t name_hash(
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name)
-{
- /* Using djb2 hash by Dan Bernstein */
- uint64_t hash = 5381;
-
- /* Calculate hash over GUID */
- hash = ((hash << 5) + hash) + guid->Data1;
- hash = ((hash << 5) + hash) + guid->Data2;
- hash = ((hash << 5) + hash) + guid->Data3;
-
- for (int i = 0; i < 8; ++i) {
-
- hash = ((hash << 5) + hash) + guid->Data4[i];
- }
-
- /* Extend to cover name up to but not including null terminator */
- for (int i = 0; i < name_size / sizeof(int16_t); ++i) {
-
- if (!name[i]) break;
- hash = ((hash << 5) + hash) + name[i];
- }
-
- return hash;
-}
-
-static uint64_t generate_uid(
- const struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name)
-{
- uint64_t uid = name_hash(guid, name_size, name);
-
- /* todo - handle collision */
- (void)context;
-
- return uid;
-}
-
-static int find_variable(
- const struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name)
-{
- int found_pos = -1;
- uint64_t uid = name_hash(guid, name_size, name);
-
- for (int pos = 0; pos < context->max_variables; pos++) {
-
- if ((context->entries[pos].in_use) &&
- (uid == context->entries[pos].info.metadata.uid)) {
-
- found_pos = pos;
- break;
- }
- }
-
- return found_pos;
-}
-
-static int find_free(
- const struct variable_index *context)
-{
- int free_pos = -1;
-
- for (int pos = 0; pos < context->max_variables; pos++) {
-
- if (!context->entries[pos].in_use) {
-
- free_pos = pos;
- break;
- }
- }
-
- return free_pos;
-}
-
-static void mark_dirty(struct variable_entry *entry)
-{
- if (entry->info.metadata.attributes & EFI_VARIABLE_NON_VOLATILE)
- entry->dirty = true;
-}
-
-static struct variable_entry *containing_entry(const struct variable_info *info)
-{
- size_t info_offset = offsetof(struct variable_entry, info);
- struct variable_entry *entry = (struct variable_entry*)((uint8_t*)info - info_offset);
- return entry;
-}
-
-/* Public functions */
-efi_status_t variable_index_init(
- struct variable_index *context,
- size_t max_variables)
-{
- context->max_variables = max_variables;
- context->entries = (struct variable_entry*)
- malloc(sizeof(struct variable_entry) * max_variables);
-
- if (context->entries) {
- memset(context->entries, 0, sizeof(struct variable_entry) * max_variables);
- }
-
- return (context->entries) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
-}
-
-void variable_index_deinit(
- struct variable_index *context)
-{
- free(context->entries);
-}
-
-size_t variable_index_max_dump_size(
- struct variable_index *context)
-{
- return sizeof(struct variable_metadata) * context->max_variables;
-}
-
-const struct variable_info *variable_index_find(
- const struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name)
-{
- const struct variable_info *result = NULL;
- int pos = find_variable(context, guid, name_size, name);
-
- if (pos >= 0) {
-
- result = &context->entries[pos].info;
- }
-
- return result;
-}
-
-const struct variable_info *variable_index_find_next(
- const struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name)
-{
- const struct variable_info *result = NULL;
-
- if (name_size >= sizeof(int16_t)) {
-
- /*
- * Name must be at least one character long to accommodate
- * the mandatory null terminator.
- */
- if (name[0] != 0) {
-
- /* Find next from current name */
- int pos = find_variable(context, guid, name_size, name);
-
- if (pos >= 0) {
-
- /* Iterate to next used entry */
- ++pos;
- while (pos < context->max_variables) {
-
- if (context->entries[pos].in_use &&
- context->entries[pos].info.is_variable_set) {
-
- result = &context->entries[pos].info;
- break;
- }
-
- ++pos;
- }
- }
- }
- else {
-
- /* Find first */
- int pos = 0;
-
- while (pos < context->max_variables) {
-
- if (context->entries[pos].in_use &&
- context->entries[pos].info.is_variable_set) {
-
- result = &context->entries[pos].info;
- break;
- }
-
- ++pos;
- }
- }
- }
-
- return result;
-}
-
-static void set_variable_name(
- struct variable_info *info,
- size_t name_size,
- const int16_t *name)
-{
- size_t trimmed_size = 0;
-
- /* Trim the saved name to only include a single null terminator.
- * Any additional terminators included in the client-set name size
- * are discarded.
- */
- for (size_t i = 0; i < name_size; i++) {
-
- ++trimmed_size;
- info->metadata.name[i] = name[i];
-
- if (!name[i]) break;
- }
-
- info->metadata.name_size = trimmed_size * sizeof(int16_t);
-}
-
-static struct variable_entry *add_entry(
- struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name)
-{
- struct variable_entry *entry = NULL;
-
- if (name_size <= (VARIABLE_INDEX_MAX_NAME_SIZE * sizeof(int16_t))) {
-
- int pos = find_free(context);
-
- if (pos >= 0) {
-
- entry = &context->entries[pos];
-
- struct variable_info *info = &entry->info;
-
- /* Initialize metadata */
- info->metadata.uid = generate_uid(context, guid, name_size, name);
- info->metadata.guid = *guid;
- info->metadata.attributes = 0;
- set_variable_name(info, name_size, name);
-
- info->is_constraints_set = false;
- info->is_variable_set = false;
-
- entry->in_use = true;
- }
- }
-
- return entry;
-}
-
-const struct variable_info *variable_index_add_variable(
- struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name,
- uint32_t attributes)
-{
- struct variable_info *info = NULL;
- struct variable_entry *entry = add_entry(context, guid, name_size, name);
-
- if (entry) {
-
- info = &entry->info;
-
- info->metadata.attributes = attributes;
- info->is_variable_set = true;
-
- mark_dirty(entry);
- }
-
- return info;
-}
-
-const struct variable_info *variable_index_add_constraints(
- struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name,
- const struct variable_constraints *constraints)
-{
- struct variable_info *info = NULL;
- struct variable_entry *entry = add_entry(context, guid, name_size, name);
-
- if (entry) {
-
- info = &entry->info;
-
- info->check_constraints = *constraints;
- info->is_constraints_set = true;
- }
-
- return info;
-}
-
-void variable_index_remove_variable(
- struct variable_index *context,
- const struct variable_info *info)
-{
- if (info) {
-
- struct variable_entry *entry = containing_entry(info);
- mark_dirty(entry);
-
- /* Mark variable as no longer set */
- entry->info.is_variable_set = false;
-
- /* Entry may still be needed if check constraints were set */
- entry->in_use = info->is_constraints_set;
-
- if (!entry->in_use) {
-
- /* Entry not needed so wipe */
- memset(&entry->info, 0, sizeof(struct variable_info));
- }
- }
-}
-
-void variable_index_update_variable(
- const struct variable_info *info,
- uint32_t attributes)
-{
- if (info) {
-
- struct variable_info *modified_info = (struct variable_info*)info;
- struct variable_entry *entry = containing_entry(modified_info);
-
- if (!modified_info->is_variable_set ||
- (attributes != modified_info->metadata.attributes)) {
-
- /* The update changes the variable_info state */
- modified_info->is_variable_set = true;
- modified_info->metadata.attributes = attributes;
- mark_dirty(entry);
- }
- }
-}
-
-void variable_index_update_constraints(
- const struct variable_info *info,
- const struct variable_constraints *constraints)
-{
- if (info) {
-
- struct variable_info *modified_info = (struct variable_info*)info;
-
- modified_info->check_constraints = *constraints;
- modified_info->is_constraints_set = true;
- }
-}
-
-bool variable_index_dump(
- struct variable_index *context,
- size_t buffer_size,
- uint8_t *buffer,
- size_t *data_len)
-{
- bool any_dirty = false;
- uint8_t *dump_pos = buffer;
- size_t bytes_dumped = 0;
-
- for (int pos = 0; pos < context->max_variables; pos++) {
-
- struct variable_entry *entry = &context->entries[pos];
- struct variable_metadata *metadata = &entry->info.metadata;
-
- if (entry->in_use &&
- entry->info.is_variable_set &&
- (metadata->attributes & EFI_VARIABLE_NON_VOLATILE) &&
- ((bytes_dumped + sizeof(struct variable_metadata)) <= buffer_size)) {
-
- memcpy(dump_pos, metadata, sizeof(struct variable_metadata));
- bytes_dumped += sizeof(struct variable_metadata);
- dump_pos += sizeof(struct variable_metadata);
- }
-
- any_dirty |= entry->dirty;
- entry->dirty = false;
- }
-
- *data_len = bytes_dumped;
-
- return any_dirty;
-}
-
-size_t variable_index_restore(
- const struct variable_index *context,
- size_t data_len,
- const uint8_t *buffer)
-{
- size_t bytes_loaded = 0;
- const uint8_t *load_pos = buffer;
- int pos = 0;
-
- while (bytes_loaded < data_len) {
-
- if ((data_len - bytes_loaded) >= sizeof(struct variable_metadata)) {
-
- struct variable_entry *entry = &context->entries[pos];
- struct variable_metadata *metadata = &entry->info.metadata;
-
- memcpy(metadata, load_pos, sizeof(struct variable_metadata));
-
- entry->info.is_variable_set = true;
- entry->in_use = true;
-
- bytes_loaded += sizeof(struct variable_metadata);
- load_pos += sizeof(struct variable_metadata);
-
- ++pos;
- }
- else {
-
- /* Not a whole number of variable_metadata structs! */
- break;
- }
- }
-
- return bytes_loaded;
-}
diff --git a/components/service/smm_variable/backend/variable_index_iterator.c b/components/service/smm_variable/backend/variable_index_iterator.c
deleted file mode 100644
index 7cc6dc7a7..000000000
--- a/components/service/smm_variable/backend/variable_index_iterator.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include <stddef.h>
-#include "variable_index_iterator.h"
-
-void variable_index_iterator_first(
- struct variable_index_iterator *iter,
- const struct variable_index *variable_index)
-{
- iter->variable_index = variable_index;
- iter->current_pos = variable_index->max_variables;
-
- for (size_t pos = 0; pos < variable_index->max_variables; pos++) {
-
- if (variable_index->entries[pos].in_use) {
-
- iter->current_pos = pos;
- break;
- }
- }
-}
-
-bool variable_index_iterator_is_done(
- const struct variable_index_iterator *iter)
-{
- return iter->current_pos >= iter->variable_index->max_variables;
-}
-
-const struct variable_info *variable_index_iterator_current(
- const struct variable_index_iterator *iter)
-{
- const struct variable_info *current = NULL;
-
- if (!variable_index_iterator_is_done(iter)) {
-
- current = &iter->variable_index->entries[iter->current_pos].info;
- }
-
- return current;
-}
-
-void variable_index_iterator_next(
- struct variable_index_iterator *iter)
-{
- size_t next_pos = iter->current_pos;
-
- while (next_pos < iter->variable_index->max_variables) {
-
- ++next_pos;
- if (iter->variable_index->entries[next_pos].in_use) break;
- }
-
- iter->current_pos = next_pos;
-}
diff --git a/components/service/smm_variable/client/cpp/smm_variable_client.cpp b/components/service/smm_variable/client/cpp/smm_variable_client.cpp
deleted file mode 100644
index a68b7acec..000000000
--- a/components/service/smm_variable/client/cpp/smm_variable_client.cpp
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <cstring>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <rpc_caller.h>
-#include "smm_variable_client.h"
-
-smm_variable_client::smm_variable_client() :
- m_caller(NULL),
- m_err_rpc_status(TS_RPC_CALL_ACCEPTED)
-{
-
-}
-
-smm_variable_client::smm_variable_client(
- struct rpc_caller *caller) :
- m_caller(caller),
- m_err_rpc_status(TS_RPC_CALL_ACCEPTED)
-{
-
-}
-
-smm_variable_client::~smm_variable_client()
-{
-
-}
-
-void smm_variable_client::set_caller(struct rpc_caller *caller)
-{
- m_caller = caller;
-}
-
-int smm_variable_client::err_rpc_status() const
-{
- return m_err_rpc_status;
-}
-
-efi_status_t smm_variable_client::set_variable(
- const EFI_GUID &guid,
- const std::wstring &name,
- const std::string &data,
- uint32_t attributes)
-{
- return set_variable(
- guid,
- name,
- data,
- attributes,
- 0, 0);
-}
-
-efi_status_t smm_variable_client::set_variable(
- const EFI_GUID &guid,
- const std::wstring &name,
- const std::string &data,
- uint32_t attributes,
- size_t override_name_size,
- size_t override_data_size)
-{
- efi_status_t efi_status = EFI_NOT_READY;
-
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
- size_t data_size = data.size();
- size_t req_len = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, data_size);
-
- rpc_call_handle call_handle;
- uint8_t *req_buf;
-
- call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
- if (call_handle) {
-
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
-
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_var =
- (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)req_buf;
-
- access_var->Guid = guid;
- access_var->NameSize = name_size;
- access_var->DataSize = data_size;
- access_var->Attributes = attributes;
-
- memcpy(access_var->Name, var_name.data(), name_size);
- memcpy(&req_buf[SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_var)],
- data.data(), data_size);
-
- /* To support invalid size testing, use overrides if set */
- if (override_name_size) access_var->NameSize = override_name_size;
- if (override_data_size) access_var->DataSize = override_data_size;
-
- m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
- SMM_VARIABLE_FUNCTION_SET_VARIABLE, &opstatus, &resp_buf, &resp_len);
-
- if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- efi_status = opstatus;
- }
- else {
-
- efi_status = rpc_to_efi_status();
- }
-
- rpc_caller_end(m_caller, call_handle);
- }
-
- return efi_status;
-}
-
-efi_status_t smm_variable_client::get_variable(
- const EFI_GUID &guid,
- const std::wstring &name,
- std::string &data)
-{
- return get_variable(
- guid,
- name,
- data,
- 0);
-}
-
-efi_status_t smm_variable_client::get_variable(
- const EFI_GUID &guid,
- const std::wstring &name,
- std::string &data,
- size_t override_name_size)
-{
- efi_status_t efi_status = EFI_NOT_READY;
-
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
- size_t data_size = 0;
- size_t req_len = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, data_size);
-
- rpc_call_handle call_handle;
- uint8_t *req_buf;
-
- call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
- if (call_handle) {
-
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
-
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_var =
- (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)req_buf;
-
- access_var->Guid = guid;
- access_var->NameSize = name_size;
- access_var->DataSize = data_size;
-
- memcpy(access_var->Name, var_name.data(), name_size);
-
- /* To support invalid size testing, use overrides if set */
- if (override_name_size) access_var->NameSize = override_name_size;
-
- m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
- SMM_VARIABLE_FUNCTION_GET_VARIABLE, &opstatus, &resp_buf, &resp_len);
-
- if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- efi_status = opstatus;
-
- if (efi_status == EFI_SUCCESS) {
-
- efi_status = EFI_PROTOCOL_ERROR;
-
- if (resp_len >= SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET) {
-
- access_var = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)resp_buf;
-
- if (resp_len >=
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_TOTAL_SIZE(access_var)) {
-
- data_size = access_var->DataSize;
- const char *data_start = (const char*)
- &resp_buf[
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_var)];
-
- data.assign(data_start, data_size);
- efi_status = EFI_SUCCESS;
- }
- }
- }
- }
- else {
-
- efi_status = rpc_to_efi_status();
- }
-
- rpc_caller_end(m_caller, call_handle);
- }
-
- return efi_status;
-}
-
-efi_status_t smm_variable_client::remove_variable(
- const EFI_GUID &guid,
- const std::wstring &name)
-{
- /* Variable is removed by performing a 'set' with zero length data */
- return set_variable(guid, name, std::string(), 0);
-}
-
-efi_status_t smm_variable_client::get_next_variable_name(
- EFI_GUID &guid,
- std::wstring &name)
-{
- return get_next_variable_name(
- guid,
- name,
- 0);
-}
-
-efi_status_t smm_variable_client::get_next_variable_name(
- EFI_GUID &guid,
- std::wstring &name,
- size_t override_name_size)
-{
- efi_status_t efi_status = EFI_NOT_READY;
-
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
- size_t req_len = SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_SIZE(name_size);
-
- rpc_call_handle call_handle;
- uint8_t *req_buf;
-
- call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
- if (call_handle) {
-
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
-
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *next_var =
- (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)req_buf;
-
- next_var->Guid = guid;
- next_var->NameSize = name_size;
-
- memcpy(next_var->Name, var_name.data(), name_size);
-
- /* To support invalid size testing, use overrides if set */
- if (override_name_size) next_var->NameSize = override_name_size;
-
- m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
- SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, &opstatus, &resp_buf, &resp_len);
-
- if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- efi_status = opstatus;
-
- if (efi_status == EFI_SUCCESS) {
-
- efi_status = EFI_PROTOCOL_ERROR;
-
- if (resp_len >= SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET) {
-
- next_var = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)resp_buf;
-
- if (resp_len >=
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_TOTAL_SIZE(next_var)) {
-
- guid = next_var->Guid;
- name = from_variable_name(next_var->Name, next_var->NameSize);
-
- efi_status = EFI_SUCCESS;
- }
- }
- }
- }
- else {
-
- efi_status = rpc_to_efi_status();
- }
-
- rpc_caller_end(m_caller, call_handle);
- }
-
- return efi_status;
-}
-
-efi_status_t smm_variable_client::exit_boot_service()
-{
- efi_status_t efi_status = EFI_NOT_READY;
-
- size_t req_len = 0;
- rpc_call_handle call_handle;
- uint8_t *req_buf;
-
- call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
- if (call_handle) {
-
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
-
- m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
- SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, &opstatus, &resp_buf, &resp_len);
-
- if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- efi_status = opstatus;
- }
- else {
-
- efi_status = rpc_to_efi_status();
- }
-
- rpc_caller_end(m_caller, call_handle);
- }
-
- return efi_status;
-}
-
-efi_status_t smm_variable_client::set_var_check_property(
- const EFI_GUID &guid,
- const std::wstring &name,
- const VAR_CHECK_VARIABLE_PROPERTY &check_property)
-{
- return set_var_check_property(
- guid,
- name,
- check_property,
- 0);
-}
-
-efi_status_t smm_variable_client::set_var_check_property(
- const EFI_GUID &guid,
- const std::wstring &name,
- const VAR_CHECK_VARIABLE_PROPERTY &check_property,
- size_t override_name_size)
-{
- efi_status_t efi_status = EFI_NOT_READY;
-
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
- size_t req_len = SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size);
-
- rpc_call_handle call_handle;
- uint8_t *req_buf;
-
- call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
- if (call_handle) {
-
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
-
- SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *req_msg =
- (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY*)req_buf;
-
- req_msg->Guid = guid;
- req_msg->NameSize = name_size;
- req_msg->VariableProperty = check_property;
-
- memcpy(req_msg->Name, var_name.data(), name_size);
-
- /* To support invalid size testing, use override if set */
- if (override_name_size) req_msg->NameSize = override_name_size;
-
- m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
- SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET, &opstatus,
- &resp_buf, &resp_len);
-
- if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- efi_status = opstatus;
- }
- else {
-
- efi_status = rpc_to_efi_status();
- }
-
- rpc_caller_end(m_caller, call_handle);
- }
-
- return efi_status;
-}
-
-efi_status_t smm_variable_client::get_var_check_property(
- const EFI_GUID &guid,
- const std::wstring &name,
- VAR_CHECK_VARIABLE_PROPERTY &check_property)
-{
- return get_var_check_property(
- guid,
- name,
- check_property,
- 0);
-}
-
-efi_status_t smm_variable_client::get_var_check_property(
- const EFI_GUID &guid,
- const std::wstring &name,
- VAR_CHECK_VARIABLE_PROPERTY &check_property,
- size_t override_name_size)
-{
- efi_status_t efi_status = EFI_NOT_READY;
-
- std::vector<int16_t> var_name = to_variable_name(name);
- size_t name_size = var_name.size() * sizeof(int16_t);
- size_t req_len = SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size);
-
- rpc_call_handle call_handle;
- uint8_t *req_buf;
-
- call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
- if (call_handle) {
-
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
-
- SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *req_msg =
- (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY*)req_buf;
-
- req_msg->Guid = guid;
- req_msg->NameSize = name_size;
-
- memcpy(req_msg->Name, var_name.data(), name_size);
-
- /* To support invalid size testing, use overrides if set */
- if (override_name_size) req_msg->NameSize = override_name_size;
-
- m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
- SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, &opstatus,
- &resp_buf, &resp_len);
-
- if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- efi_status = opstatus;
-
- if (efi_status == EFI_SUCCESS) {
-
- efi_status = EFI_PROTOCOL_ERROR;
-
- if (resp_len >= SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_NAME_OFFSET) {
-
- SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *resp_msg =
- (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY*)resp_buf;
-
- if (resp_len >=
- SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_TOTAL_SIZE(resp_msg)) {
-
- check_property = resp_msg->VariableProperty;
- efi_status = EFI_SUCCESS;
- }
- }
- }
- }
- else {
-
- efi_status = rpc_to_efi_status();
- }
-
- rpc_caller_end(m_caller, call_handle);
- }
-
- return efi_status;
-}
-
-efi_status_t smm_variable_client::get_payload_size(
- size_t &payload_size)
-{
- efi_status_t efi_status = EFI_NOT_READY;
-
- size_t req_len = 0;
- rpc_call_handle call_handle;
- uint8_t *req_buf;
-
- call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
- if (call_handle) {
-
- uint8_t *resp_buf;
- size_t resp_len;
- rpc_opstatus_t opstatus;
-
- m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
- SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, &opstatus, &resp_buf, &resp_len);
-
- if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
- efi_status = opstatus;
-
- if (efi_status == EFI_SUCCESS) {
-
- if (resp_len >= sizeof(SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {
-
- SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *resp_msg =
- (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE*)resp_buf;
-
- payload_size = resp_msg->VariablePayloadSize;
- }
- else {
-
- efi_status = EFI_PROTOCOL_ERROR;
- }
- }
- }
- else {
-
- efi_status = rpc_to_efi_status();
- }
-
- rpc_caller_end(m_caller, call_handle);
- }
-
- return efi_status;
-}
-
-efi_status_t smm_variable_client::rpc_to_efi_status() const
-{
- efi_status_t efi_status = EFI_INVALID_PARAMETER;
-
- switch (m_err_rpc_status)
- {
- case TS_RPC_ERROR_EP_DOES_NOT_EXIT:
- efi_status = EFI_UNSUPPORTED;
- break;
- case TS_RPC_ERROR_INVALID_OPCODE:
- efi_status = EFI_UNSUPPORTED;
- break;
- case TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED:
- efi_status = EFI_PROTOCOL_ERROR;
- break;
- case TS_RPC_ERROR_INVALID_REQ_BODY:
- efi_status = EFI_PROTOCOL_ERROR;
- break;
- case TS_RPC_ERROR_INVALID_RESP_BODY:
- efi_status = EFI_DEVICE_ERROR;
- break;
- case TS_RPC_ERROR_RESOURCE_FAILURE:
- efi_status = EFI_OUT_OF_RESOURCES;
- break;
- case TS_RPC_ERROR_NOT_READY:
- efi_status = EFI_NOT_READY;
- break;
- case TS_RPC_ERROR_INVALID_TRANSACTION:
- efi_status = EFI_INVALID_PARAMETER;
- break;
- case TS_RPC_ERROR_INTERNAL:
- efi_status = EFI_DEVICE_ERROR;
- break;
- case TS_RPC_ERROR_INVALID_PARAMETER:
- efi_status = EFI_INVALID_PARAMETER;
- break;
- case TS_RPC_ERROR_INTERFACE_DOES_NOT_EXIST:
- efi_status = EFI_UNSUPPORTED;
- break;
- default:
- break;
- }
-
- return efi_status;
-}
-
-std::vector<int16_t> smm_variable_client::to_variable_name(
- const std::wstring &string)
-{
- std::vector<int16_t> var_name;
-
- for (size_t i = 0; i < string.size(); i++) {
-
- var_name.push_back((int16_t)string[i]);
- }
-
- var_name.push_back(0);
-
- return var_name;
-}
-
-const std::wstring smm_variable_client::from_variable_name(
- const int16_t *var_name,
- size_t name_size)
-{
- std::wstring name;
- size_t num_chars = name_size / sizeof(int16_t);
-
- for (size_t i = 0; i < num_chars; i++) {
-
- if (!var_name[i]) break; /* Reached null terminator */
- name.push_back((wchar_t)var_name[i]);
- }
-
- return name;
-}
diff --git a/components/service/smm_variable/client/cpp/smm_variable_client.h b/components/service/smm_variable/client/cpp/smm_variable_client.h
deleted file mode 100644
index 9c36c4eb2..000000000
--- a/components/service/smm_variable/client/cpp/smm_variable_client.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SMM_VARIABLE_CLIENT_H
-#define SMM_VARIABLE_CLIENT_H
-
-#include <cstdint>
-#include <string>
-#include <vector>
-#include <protocols/common/efi/efi_status.h>
-#include <protocols/service/smm_variable/smm_variable_proto.h>
-
-struct rpc_caller;
-
-/*
- * Provides a C++ client interface for accessing an instance of the smm-variable service.
- * This client is intented for testing the UEFI variable store provided by the smm-variable
- * service.
- */
-class smm_variable_client
-{
-public:
-
- smm_variable_client();
- smm_variable_client(struct rpc_caller *caller);
- ~smm_variable_client();
-
- void set_caller(struct rpc_caller *caller);
- int err_rpc_status() const;
-
- /* Set a string type variable */
- efi_status_t set_variable(
- const EFI_GUID &guid,
- const std::wstring &name,
- const std::string &data,
- uint32_t attributes);
-
- efi_status_t set_variable(
- const EFI_GUID &guid,
- const std::wstring &name,
- const std::string &data,
- uint32_t attributes,
- size_t override_name_size,
- size_t override_data_size);
-
- /* Get a string type variable */
- efi_status_t get_variable(
- const EFI_GUID &guid,
- const std::wstring &name,
- std::string &data);
-
- efi_status_t get_variable(
- const EFI_GUID &guid,
- const std::wstring &name,
- std::string &data,
- size_t override_name_size);
-
- /* Remove a variable */
- efi_status_t remove_variable(
- const EFI_GUID &guid,
- const std::wstring &name);
-
- /* Get the next variable name - for enumerating store contents */
- efi_status_t get_next_variable_name(
- EFI_GUID &guid,
- std::wstring &name);
-
- efi_status_t get_next_variable_name(
- EFI_GUID &guid,
- std::wstring &name,
- size_t override_name_size);
-
- /* Exit boot service */
- efi_status_t exit_boot_service();
-
- /* Set variable check properties */
- efi_status_t set_var_check_property(
- const EFI_GUID &guid,
- const std::wstring &name,
- const VAR_CHECK_VARIABLE_PROPERTY &check_property);
-
- efi_status_t set_var_check_property(
- const EFI_GUID &guid,
- const std::wstring &name,
- const VAR_CHECK_VARIABLE_PROPERTY &check_property,
- size_t override_name_size);
-
- /* Get variable check properties */
- efi_status_t get_var_check_property(
- const EFI_GUID &guid,
- const std::wstring &name,
- VAR_CHECK_VARIABLE_PROPERTY &check_property);
-
- efi_status_t get_var_check_property(
- const EFI_GUID &guid,
- const std::wstring &name,
- VAR_CHECK_VARIABLE_PROPERTY &check_property,
- size_t override_name_size);
-
- /* Get maximum variable payload size */
- efi_status_t get_payload_size(
- size_t &payload_size);
-
-
-private:
- efi_status_t rpc_to_efi_status() const;
-
- static std::vector<int16_t> to_variable_name(const std::wstring &string);
- static const std::wstring from_variable_name(const int16_t *name, size_t name_size);
-
- struct rpc_caller *m_caller;
- int m_err_rpc_status;
-};
-
-#endif /* SMM_VARIABLE_CLIENT_H */
diff --git a/components/service/smm_variable/provider/smm_variable_provider.c b/components/service/smm_variable/provider/smm_variable_provider.c
deleted file mode 100644
index d239a4283..000000000
--- a/components/service/smm_variable/provider/smm_variable_provider.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-#include <string.h>
-#include <protocols/service/smm_variable/smm_variable_proto.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include "smm_variable_provider.h"
-
-/* Service request handlers */
-static rpc_status_t get_variable_handler(void *context, struct call_req *req);
-static rpc_status_t get_next_variable_name_handler(void *context, struct call_req *req);
-static rpc_status_t set_variable_handler(void *context, struct call_req *req);
-static rpc_status_t query_variable_info_handler(void *context, struct call_req *req);
-static rpc_status_t exit_boot_service_handler(void *context, struct call_req *req);
-static rpc_status_t set_var_check_property_handler(void *context, struct call_req *req);
-static rpc_status_t get_var_check_property_handler(void *context, struct call_req *req);
-static rpc_status_t get_payload_size_handler(void *context, struct call_req *req);
-
-/* Handler mapping table for service */
-static const struct service_handler handler_table[] = {
- {SMM_VARIABLE_FUNCTION_GET_VARIABLE, get_variable_handler},
- {SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, get_next_variable_name_handler},
- {SMM_VARIABLE_FUNCTION_SET_VARIABLE, set_variable_handler},
- {SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, query_variable_info_handler},
- {SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, exit_boot_service_handler},
- {SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET, set_var_check_property_handler},
- {SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, get_var_check_property_handler},
- {SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, get_payload_size_handler}
-};
-
-struct rpc_interface *smm_variable_provider_init(
- struct smm_variable_provider *context,
- uint32_t owner_id,
- size_t max_variables,
- struct storage_backend *persistent_store,
- struct storage_backend *volatile_store)
-{
- struct rpc_interface *rpc_interface = NULL;
-
- if (context) {
-
- service_provider_init(&context->base_provider, context,
- handler_table, sizeof(handler_table)/sizeof(struct service_handler));
-
- if (uefi_variable_store_init(
- &context->variable_store,
- owner_id,
- max_variables,
- persistent_store,
- volatile_store) == EFI_SUCCESS) {
-
- rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
- }
- }
-
- return rpc_interface;
-}
-
-void smm_variable_provider_deinit(struct smm_variable_provider *context)
-{
- uefi_variable_store_deinit(&context->variable_store);
-}
-
-static efi_status_t sanitize_access_variable_param(struct call_req *req, size_t *param_len)
-{
- efi_status_t efi_status = EFI_INVALID_PARAMETER;
- *param_len = 0;
- const struct call_param_buf *req_buf = call_req_get_req_buf(req);
-
- if (req_buf->data_len >= SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET) {
-
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *param =
- (const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)req_buf->data;
-
- size_t max_space_for_name = req_buf->data_len -
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
-
- if (param->NameSize <= max_space_for_name) {
-
- *param_len = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(param);
- efi_status = EFI_SUCCESS;
- }
- }
-
- return efi_status;
-}
-
-static efi_status_t sanitize_get_next_var_name_param(struct call_req *req, size_t *param_len)
-{
- efi_status_t efi_status = EFI_INVALID_PARAMETER;
- *param_len = 0;
- const struct call_param_buf *req_buf = call_req_get_req_buf(req);
-
- if (req_buf->data_len >= SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET) {
-
- const SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *param =
- (const SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)req_buf->data;
-
- size_t max_space_for_name = req_buf->data_len -
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET;
-
- if (param->NameSize <= max_space_for_name) {
-
- *param_len = SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_TOTAL_SIZE(param);
- efi_status = EFI_SUCCESS;
- }
- }
-
- return efi_status;
-}
-
-static efi_status_t sanitize_var_check_property_param(struct call_req *req, size_t *param_len)
-{
- efi_status_t efi_status = EFI_INVALID_PARAMETER;
- *param_len = 0;
- const struct call_param_buf *req_buf = call_req_get_req_buf(req);
-
- if (req_buf->data_len >= SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_NAME_OFFSET) {
-
- const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *param =
- (const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY*)req_buf->data;
-
- size_t max_space_for_name = req_buf->data_len -
- SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_NAME_OFFSET;
-
- if (param->NameSize <= max_space_for_name) {
-
- *param_len = SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_TOTAL_SIZE(param);
- efi_status = EFI_SUCCESS;
- }
- }
-
- return efi_status;
-}
-
-static rpc_status_t get_variable_handler(void *context, struct call_req *req)
-{
- struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
-
- size_t param_len = 0;
- efi_status_t efi_status = sanitize_access_variable_param(req, &param_len);
-
- if (efi_status == EFI_SUCCESS) {
-
- /* Valid access variable header parameter */
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-
- if (resp_buf->size >= param_len) {
-
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- size_t max_data_len = resp_buf->size - param_len;
-
- memmove(resp_buf->data, req_buf->data, param_len);
-
- efi_status = uefi_variable_store_get_variable(
- &this_instance->variable_store,
- (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)resp_buf->data,
- max_data_len,
- &resp_buf->data_len);
- }
- else {
-
- /* Reponse buffer not big enough */
- efi_status = EFI_BAD_BUFFER_SIZE;
- }
- }
-
- call_req_set_opstatus(req, efi_status);
-
- return TS_RPC_CALL_ACCEPTED;
-}
-
-static rpc_status_t get_next_variable_name_handler(void *context, struct call_req* req)
-{
- struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
-
- size_t param_len = 0;
- efi_status_t efi_status = sanitize_get_next_var_name_param(req, &param_len);
-
- if (efi_status == EFI_SUCCESS) {
-
- /* Valid get next variable name header */
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-
- if (resp_buf->size >= param_len) {
-
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- size_t max_name_len = resp_buf->size -
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET;
-
- memmove(resp_buf->data, req_buf->data, param_len);
-
- efi_status = uefi_variable_store_get_next_variable_name(
- &this_instance->variable_store,
- (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)resp_buf->data,
- max_name_len,
- &resp_buf->data_len);
- }
- else {
-
- /* Reponse buffer not big enough */
- efi_status = EFI_BAD_BUFFER_SIZE;
- }
- }
-
- call_req_set_opstatus(req, efi_status);
-
- return TS_RPC_CALL_ACCEPTED;
-}
-
-static rpc_status_t set_variable_handler(void *context, struct call_req* req)
-{
- struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
-
- size_t param_len = 0;
- efi_status_t efi_status = sanitize_access_variable_param(req, &param_len);
-
- if (efi_status == EFI_SUCCESS) {
-
- /* Access variable header is whole. Check that buffer length can
- * accommodate the data.
- */
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
-
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_var =
- (const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)req_buf->data;
-
- size_t space_for_data = req_buf->data_len -
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_var);
-
- if (access_var->DataSize <= space_for_data) {
-
- efi_status = uefi_variable_store_set_variable(
- &this_instance->variable_store,
- access_var);
- }
- else {
-
- /* Invalid DataSize */
- efi_status = EFI_INVALID_PARAMETER;
- }
- }
-
- call_req_set_opstatus(req, efi_status);
-
- return TS_RPC_CALL_ACCEPTED;
-}
-
-static rpc_status_t query_variable_info_handler(void *context, struct call_req* req)
-{
- struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
-
- /* todo */
-
- return TS_RPC_ERROR_NOT_READY;
-}
-
-static rpc_status_t exit_boot_service_handler(void *context, struct call_req* req)
-{
- struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
-
- efi_status_t efi_status = uefi_variable_store_exit_boot_service(&this_instance->variable_store);
- call_req_set_opstatus(req, efi_status);
-
- return TS_RPC_CALL_ACCEPTED;
-}
-
-static rpc_status_t set_var_check_property_handler(void *context, struct call_req *req)
-{
- struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
-
- size_t param_len = 0;
- efi_status_t efi_status = sanitize_var_check_property_param(req, &param_len);
-
- if (efi_status == EFI_SUCCESS) {
-
- /* Request parameter structue looks whole */
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
-
- const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *check_property =
- (const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY*)req_buf->data;
-
- efi_status = uefi_variable_store_set_var_check_property(
- &this_instance->variable_store,
- check_property);
- }
-
- call_req_set_opstatus(req, efi_status);
-
- return TS_RPC_CALL_ACCEPTED;
-}
-
-static rpc_status_t get_var_check_property_handler(void *context, struct call_req *req)
-{
- struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
-
- size_t param_len = 0;
- efi_status_t efi_status = sanitize_var_check_property_param(req, &param_len);
-
- if (efi_status == EFI_SUCCESS) {
-
- /* Request parameter structue looks whole */
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-
- if (resp_buf->size >= param_len) {
-
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- memmove(resp_buf->data, req_buf->data, param_len);
- resp_buf->data_len = param_len;
-
- efi_status = uefi_variable_store_get_var_check_property(
- &this_instance->variable_store,
- (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY*)resp_buf->data);
- }
- else {
-
- /* Reponse buffer not big enough */
- efi_status = EFI_BAD_BUFFER_SIZE;
- }
- }
-
- call_req_set_opstatus(req, efi_status);
-
- return TS_RPC_CALL_ACCEPTED;
-}
-
-static rpc_status_t get_payload_size_handler(void *context, struct call_req *req)
-{
- struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
-
- /* Payload size is constrained by the size of the RPC call buffer. Because the variable length
- * name is also carried in the buffer, the maximum payload size depends on the name size. This
- * function therefore treats the payload as name + data.
- */
- size_t payload_size = req->req_buf.size - SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
-
- efi_status_t efi_status = EFI_SUCCESS;
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-
- if (resp_buf->size >= sizeof(SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {
-
- SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *resp_msg =
- (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE*)resp_buf->data;
-
- resp_msg->VariablePayloadSize = payload_size;
- resp_buf->data_len = sizeof(SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
- }
- else {
-
- /* Reponse buffer not big enough */
- efi_status = EFI_BAD_BUFFER_SIZE;
- }
-
- call_req_set_opstatus(req, efi_status);
-
- return TS_RPC_CALL_ACCEPTED;
-}
diff --git a/components/service/smm_variable/test/service/smm_variable_service_tests.cpp b/components/service/smm_variable/test/service/smm_variable_service_tests.cpp
deleted file mode 100644
index d76d9ccef..000000000
--- a/components/service/smm_variable/test/service/smm_variable_service_tests.cpp
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <service/smm_variable/client/cpp/smm_variable_client.h>
-#include <protocols/rpc/common/packed-c/encoding.h>
-#include <service_locator.h>
-#include <CppUTest/TestHarness.h>
-
-/*
- * Service-level tests for the smm-variable service.
- */
-TEST_GROUP(SmmVariableServiceTests)
-{
- void setup()
- {
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
- m_service_context = NULL;
-
- service_locator_init();
-
- m_service_context =
- service_locator_query("sn:trustedfirmware.org:smm-variable:0", &status);
- CHECK_TRUE(m_service_context);
-
- m_rpc_session_handle =
- service_context_open(m_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
-
- m_client = new smm_variable_client(caller);
-
- setup_common_guid();
- }
-
- void teardown()
- {
- delete m_client;
- m_client = NULL;
-
- service_context_close(m_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
-
- service_context_relinquish(m_service_context);
- m_service_context = NULL;
- }
-
- void setup_common_guid()
- {
- m_common_guid.Data1 = 0x12341234;
- m_common_guid.Data2 = 0x1234;
- m_common_guid.Data3 = 0x1234;
- m_common_guid.Data4[0] = 0x00;
- m_common_guid.Data4[1] = 0x01;
- m_common_guid.Data4[2] = 0x02;
- m_common_guid.Data4[3] = 0x03;
- m_common_guid.Data4[4] = 0x04;
- m_common_guid.Data4[5] = 0x05;
- m_common_guid.Data4[6] = 0x06;
- m_common_guid.Data4[7] = 0x07;
- }
-
- /* This test makes the irreversible transition from boot to runtime
- * state, leaving a variable that can't be removed. To prevent this from
- * breaking the variable enumeration test, this test is called from
- * the enumeration test to guarantee the order.
- */
- void runtimeStateAccessControl()
- {
- efi_status_t efi_status = EFI_SUCCESS;
- std::wstring boot_var_name = L"a boot variable";
- std::string boot_set_data = "Only accessible during boot";
- std::wstring runtime_var_name = L"a runtime variable";
- std::string runtime_set_data = "Only accessible during runtime";
- std::string get_data;
-
- /* This test can only successfully be run once as it exits
- * boot service, blocking access to the added boot variable.
- * If the boot variable already exists at the start of the
- * test, indicating a subsequent test run, just return.
- */
- efi_status = m_client->get_variable(
- m_common_guid,
- boot_var_name,
- get_data);
- if (efi_status == EFI_ACCESS_DENIED) return;
-
- /* Add variables with runtime state access control */
- efi_status = m_client->set_variable(
- m_common_guid,
- boot_var_name,
- boot_set_data,
- EFI_VARIABLE_BOOTSERVICE_ACCESS);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- efi_status = m_client->set_variable(
- m_common_guid,
- runtime_var_name,
- runtime_set_data,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Expect access to boot variable to be permitted */
- efi_status = m_client->get_variable(
- m_common_guid,
- boot_var_name,
- get_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- UNSIGNED_LONGS_EQUAL(boot_set_data.size(), get_data.size());
- LONGS_EQUAL(0, get_data.compare(boot_set_data));
-
- /* Expect access to the runtime variable to be forbidden during boot */
- efi_status = m_client->get_variable(
- m_common_guid,
- runtime_var_name,
- get_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_ACCESS_DENIED, efi_status);
-
- /* Exit boot service - access should no longer be permitted */
- efi_status = m_client->exit_boot_service();
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Access to the boot variablel should now be forbidden */
- efi_status = m_client->get_variable(
- m_common_guid,
- boot_var_name,
- get_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_ACCESS_DENIED, efi_status);
-
- /* Expect access to the runtime variable to now be permitted */
- efi_status = m_client->get_variable(
- m_common_guid,
- runtime_var_name,
- get_data);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- UNSIGNED_LONGS_EQUAL(runtime_set_data.size(), get_data.size());
- LONGS_EQUAL(0, get_data.compare(runtime_set_data));
-
- /* Expect removing boot variable to be forbidden */
- efi_status = m_client->remove_variable(m_common_guid, boot_var_name);
- UNSIGNED_LONGLONGS_EQUAL(EFI_ACCESS_DENIED, efi_status);
-
- /* Expect removing runtime variable to be permitted */
- efi_status = m_client->remove_variable(m_common_guid, runtime_var_name);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- }
-
- /* This test also leaves an unremovable variable */
- void setReadOnlyConstraint()
- {
- efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name_1 = L"ro_variable";
- std::string set_data = "A read only variable";
-
- /* Add a variable to the store */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_1,
- set_data,
- 0);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Apply a check to constrain to Read Only */
- VAR_CHECK_VARIABLE_PROPERTY check_property;
- check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
- check_property.Attributes = 0;
- check_property.Property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
- check_property.MinSize = 0;
- check_property.MaxSize = 100;
-
- efi_status = m_client->set_var_check_property(
- m_common_guid,
- var_name_1,
- check_property);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Read back the check property constraint and expect it to match the set value */
- VAR_CHECK_VARIABLE_PROPERTY got_check_property;
-
- efi_status = m_client->get_var_check_property(
- m_common_guid,
- var_name_1,
- got_check_property);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- UNSIGNED_LONGS_EQUAL(check_property.Revision, got_check_property.Revision);
- UNSIGNED_LONGS_EQUAL(check_property.Attributes, got_check_property.Attributes);
- UNSIGNED_LONGS_EQUAL(check_property.Property, got_check_property.Property);
- UNSIGNED_LONGS_EQUAL(check_property.MinSize, got_check_property.MinSize);
- UNSIGNED_LONGS_EQUAL(check_property.MaxSize, got_check_property.MaxSize);
-
- /* Attempt to modify variable */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_1,
- std::string("Different variable data"),
- 0);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_WRITE_PROTECTED, efi_status);
-
- /* Expect to still be able to read variable */
- std::string get_data;
-
- efi_status = m_client->get_variable(
- m_common_guid,
- var_name_1,
- get_data);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Variable value should be unmodified */
- UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
- LONGS_EQUAL(0, get_data.compare(set_data));
- }
-
- smm_variable_client *m_client;
- rpc_session_handle m_rpc_session_handle;
- struct service_context *m_service_context;
- EFI_GUID m_common_guid;
-};
-
-TEST(SmmVariableServiceTests, setAndGet)
-{
- efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
- std::string set_data = "UEFI variable data string";
- std::string get_data;
-
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name,
- set_data,
- 0);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- efi_status = m_client->get_variable(
- m_common_guid,
- var_name,
- get_data);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
- LONGS_EQUAL(0, get_data.compare(set_data));
-
- /* Expect remove to be permitted */
- efi_status = m_client->remove_variable(m_common_guid, var_name);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-}
-
-TEST(SmmVariableServiceTests, setAndGetNv)
-{
- efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"an NV test_variable";
- std::string set_data = "Another UEFI variable data string";
- std::string get_data;
-
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name,
- set_data,
- EFI_VARIABLE_NON_VOLATILE);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- efi_status = m_client->get_variable(
- m_common_guid,
- var_name,
- get_data);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
- LONGS_EQUAL(0, get_data.compare(set_data));
-
- /* Expect remove to be permitted */
- efi_status = m_client->remove_variable(m_common_guid, var_name);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-}
-
-TEST(SmmVariableServiceTests, enumerateStoreContents)
-{
- efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name_1 = L"varibale_1";
- std::wstring var_name_2 = L"varibale_2";
- std::wstring var_name_3 = L"varibale_3";
- std::string set_data = "Some variable data";
-
- /* Add some variables to the store */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_1,
- set_data,
- EFI_VARIABLE_NON_VOLATILE);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_2,
- set_data,
- EFI_VARIABLE_NON_VOLATILE);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_3,
- set_data,
- 0);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Enumerate store contents - expect the values we added */
- std::wstring var_name;
- EFI_GUID guid = {0};
-
- efi_status = m_client->get_next_variable_name(guid, var_name);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- UNSIGNED_LONGS_EQUAL(var_name_1.size(), var_name.size());
- LONGS_EQUAL(0, var_name.compare(var_name_1));
-
- efi_status = m_client->get_next_variable_name(guid, var_name);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- UNSIGNED_LONGS_EQUAL(var_name_2.size(), var_name.size());
- LONGS_EQUAL(0, var_name.compare(var_name_2));
-
- efi_status = m_client->get_next_variable_name(guid, var_name);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- UNSIGNED_LONGS_EQUAL(var_name_3.size(), var_name.size());
- LONGS_EQUAL(0, var_name.compare(var_name_3));
-
- efi_status = m_client->get_next_variable_name(guid, var_name);
- UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
-
- /* Expect to be able to remove all variables */
- efi_status = m_client->remove_variable(m_common_guid, var_name_1);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- efi_status = m_client->remove_variable(m_common_guid, var_name_2);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- efi_status = m_client->remove_variable(m_common_guid, var_name_3);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Now that the enumeration test is completed, it's safe to
- * run tests that leavev variables behind.
- */
- runtimeStateAccessControl();
- setReadOnlyConstraint();
-}
-
-TEST(SmmVariableServiceTests, setSizeConstraint)
-{
- efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name_1 = L"size_limited_variable";
- std::string set_data = "Initial value";
-
- /* Add a variable to the store */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_1,
- set_data,
- 0);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Apply a check to constrain the variable size */
- VAR_CHECK_VARIABLE_PROPERTY check_property;
- check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
- check_property.Attributes = 0;
- check_property.Property = 0;
- check_property.MinSize = 0;
- check_property.MaxSize = 20;
-
- efi_status = m_client->set_var_check_property(
- m_common_guid,
- var_name_1,
- check_property);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Attempt to set value to a size that exceeds the MaxSize constraint */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_1,
- std::string("A data value that exceeds the MaxSize constraint"),
- 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
-
- /* But setting a value that's within the constraints should work */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_1,
- std::string("Small value"),
- 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Removing should be allowed though */
- efi_status = m_client->remove_variable(m_common_guid, var_name_1);
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
-
- /* Although the variable has been removed, the constraint should
- * still be set.
- */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_1,
- std::string("Another try to set a value that exceeds the MaxSize constraint"),
- 0);
- UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
-}
-
-TEST(SmmVariableServiceTests, checkMaxVariablePayload)
-{
- efi_status_t efi_status = EFI_SUCCESS;
- size_t max_payload_size = 0;
-
- /* Expect to read a reasonable size for the variable payload */
- efi_status = m_client->get_payload_size(max_payload_size);
-
- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- CHECK_TRUE(max_payload_size >= 1024);
- CHECK_TRUE(max_payload_size <= 64 * 1024);
-}
diff --git a/deployments/internal-trusted-storage/opteesp/optee_sp_user_defines.h b/components/service/spm_test/optee_sp_user_defines.h
index e773055c4..da484c042 100644
--- a/deployments/internal-trusted-storage/opteesp/optee_sp_user_defines.h
+++ b/components/service/spm_test/optee_sp_user_defines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,8 +8,6 @@
#define SP_HEADER_DEFINES_H
/* To get UUID definition */
-#include "sp.h"
-
#define OPTEE_SP_FLAGS 0
/* Provisioned stack size */
diff --git a/components/service/spm_test/sp.c b/components/service/spm_test/sp.c
new file mode 100644
index 000000000..0b75d94ed
--- /dev/null
+++ b/components/service/spm_test/sp.c
@@ -0,0 +1,1031 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ffa_api.h>
+#include <ffa_internal_api.h>
+#include <ffa_memory_descriptors.h>
+#include <sp_api.h>
+#include <sp_discovery.h>
+#include <sp_memory_management.h>
+#include <sp_rxtx.h>
+#include <string.h>
+#include <trace.h>
+
+#include "config/interface/config_store.h"
+#include "config/loader/sp/sp_config_loader.h"
+#include "config/ramstore/config_ramstore.h"
+#include "platform/interface/memory_region.h"
+#define SP_TEST_OK 0xaa
+
+static volatile uint8_t tx_buffer[4096] __aligned(4096);
+static volatile uint8_t rx_buffer[4096] __aligned(4096);
+static volatile uint8_t my_buf[4096] __aligned(4096);
+static volatile uint8_t *shared_buffer;
+static size_t shared_buffer_size;
+
+
+
+enum errors {
+ ERR_OK,
+ ERR_VERSION,
+ ERR_ID_GET,
+ ERR_FEATURES,
+ ERR_SP_COMMUNICATION,
+ ERR_RXTX_MAP,
+ ERR_PARTITION,
+ ERR_RXTX_UNMAP,
+ ERR_MEM_INCORRECT_ACCESS,
+ ERR_MEM_RETRIEVE,
+ ERR_MEM_RELINQUISH,
+ ERR_SP_SHARE,
+ ERR_SP_SHARE_EXC,
+ ERR_TEST_NOT_FOUND
+};
+
+enum sp_tests {
+ EP_TEST_SP,
+ EP_TEST_SP_COMMUNICATION,
+ EP_TEST_SP_INCREASE,
+ EP_TRY_R_ACCESS,
+ EP_TRY_W_ACCESS,
+ EP_RETRIEVE,
+ EP_RELINQUISH,
+ EP_SP_MEM_SHARING,
+ EP_SP_MEM_SHARING_MULTI,
+ EP_SP_MEM_SHARING_EXC,
+ EP_SP_MEM_INCORRECT_ACCESS,
+ EP_SP_NOP,
+ EP_TEST_SP_COMMUNICATION_RESPONSE,
+};
+
+const char* sp_test_str[]= {
+ "EP_TEST_SP",
+ "EP_TEST_SP_COMMUNICATION",
+ "EP_TEST_SP_INCREASE",
+ "EP_TRY_R_ACCESS",
+ "EP_TRY_W_ACCESS",
+ "EP_RETRIEVE",
+ "EP_RELINQUISH",
+ "EP_SP_MEM_SHARING",
+ "EP_SP_MEM_SHARING_MULTI",
+ "EP_SP_MEM_SHARING_EXC",
+ "EP_SP_MEM_INCORRECT_ACCESS",
+ "EP_SP_NOP"
+};
+
+static bool test_ffa_version(void)
+{
+ sp_result result = SP_RESULT_OK;
+ uint16_t major = 0;
+ uint16_t minor = 0;
+
+ IMSG("Testing ffa_version()\n");
+
+ result = sp_discovery_ffa_version_get(&major, &minor);
+ if (result == SP_RESULT_OK) {
+ IMSG("ffa_version(): %"PRIu32".%"PRIu32"\n", major, minor);
+
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_version(): not supported\n");
+ } else {
+ EMSG("ffa_version(): unknown error %"PRId32"\n", result);
+ }
+
+ return false;
+}
+
+static bool test_ffa_id_get(uint16_t *id)
+{
+ sp_result result = SP_RESULT_OK;
+
+ IMSG("Testing ffa_id_get()\n");
+
+ result = sp_discovery_own_id_get(id);
+ if (result == SP_RESULT_OK) {
+ IMSG("ffa_id_get(): 0x%"PRIx16"\n", *id);
+
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_id_get(): not supported\n");
+ } else {
+ EMSG("ffa_id_get(): unknown error %"PRId32"\n", result);
+ }
+
+ return false;
+}
+
+static bool test_ffa_features(void)
+{
+ ffa_result result = FFA_OK;
+ struct ffa_interface_properties properties = {0};
+
+ IMSG("Testing ffa_features(FFA_RXTX_MAP)\n");
+
+ result = ffa_features(FFA_RXTX_MAP_32, &properties);
+ if (result == FFA_OK) {
+ static const char * const sizes[] = {
+ "4kB", "64kB", "16kB", "reserved"};
+ uint32_t buffer_size = properties.interface_properties[0] &
+ 0x3U;
+
+ IMSG("ffa_features(): minimum buffer size=%s\n",
+ sizes[buffer_size]);
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_features(): not supported\n");
+ } else {
+ EMSG("ffa_features(): unknown error %"PRId32"\n", result);
+ }
+ return false;
+}
+
+static bool test_ffa_rxtx_map(void)
+{
+ sp_result result = SP_RESULT_OK;
+
+ IMSG("Testing ffa_rxtx_map(%p %p, 1)\n", tx_buffer, rx_buffer);
+
+ result = sp_rxtx_buffer_map((void*)tx_buffer,(void*)rx_buffer,
+ sizeof(rx_buffer));
+ if (result == FFA_OK) {
+ IMSG("ffa_rxtx_map(): success\n");
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_rxtx_map(): not supported\n");
+ } else {
+ EMSG("ffa_rxtx_map(): unknown error %"PRId32"\n", result);
+ }
+
+ return false;
+}
+
+static bool ffa_partition_info_get_process(sp_result result, uint32_t count,
+ struct sp_partition_info *partitions)
+{
+ uint32_t i = 0;
+
+ if (result != SP_RESULT_OK) {
+ if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_partition_info_get(): not supported\n");
+ return false;
+ }
+ EMSG("ffa_partition_info_get(): unknown error %"PRId32"\n", result);
+ return false;
+ }
+ IMSG("ffa_partition_info_get(): count=%"PRIu32"\n", count);
+
+ for (i = 0; i < count; i++) {
+ IMSG("partition #%u: ID=%u, execution_count=%u \
+ direct request = %c, send direcy request = %c, \
+ indirect request = %c\n",
+ i, partitions[i].partition_id,
+ partitions[i].execution_context_count,
+ partitions[i].supports_direct_requests ? '1' : '0',
+ partitions[i].can_send_direct_requests ? '1' : '0',
+ partitions[i].supports_indirect_requests ? '1' : '0'
+ );
+ }
+
+ IMSG("Testing ffa_rx_release()\n");
+
+ result = ffa_rx_release();
+ if (result == FFA_OK) {
+ IMSG("ffa_rx_release(): success\n");
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_rx_release(): not supported\n");
+ return false;
+ }
+
+ EMSG("ffa_rx_release(): unknown error %"PRId32"\n", result);
+ return false;
+}
+
+static bool test_ffa_partition_info_get(void)
+{
+ sp_result result = SP_RESULT_OK;
+ struct sp_partition_info partitions[10] = {0};
+ uint32_t count = 10;
+ struct sp_uuid uuid = {.uuid = {0x23, 0xeb, 0x01, 0x00, 0xe3, 0x2a,
+ 0x44, 0x97, 0x90, 0x52, 0x2f, 0x11,
+ 0xe5, 0x84, 0xaf, 0xa6}};
+
+ IMSG("Testing ffa_partition_info_get(nil)\n");
+
+ result = sp_discovery_partition_info_get_all(partitions, &count);
+ if (!ffa_partition_info_get_process(result, count, partitions))
+ return false;
+ result = sp_discovery_partition_info_get(&uuid,
+ partitions,
+ &count);
+
+ if (!ffa_partition_info_get_process(result, count, partitions))
+ return false;
+ if (count < 2) {
+ EMSG("ffa_partition_info_get(): Returned not enough SPs count=%"PRIu32"\n", count);
+ return false;
+ }
+ return true;
+}
+
+static bool test_ffa_rxtx_unmap()
+{
+ sp_result result = SP_RESULT_OK;
+
+ result = sp_rxtx_buffer_unmap();
+ if (result == SP_RESULT_OK) {
+ IMSG("sp_rxtx_buffer_unmap(): success\n");
+ return true;
+ }
+ EMSG("sp_rxtx_buffer_unmap(): unknown error %"PRId32"\n", result);
+ return false;
+}
+
+static void return_error(uint32_t error, struct ffa_direct_msg *msg)
+{
+ ffa_msg_send_direct_resp_64(msg->destination_id, msg->source_id, 0xff,
+ error, 0, 0, 0, msg);
+}
+
+static void return_ok(struct ffa_direct_msg *msg)
+{
+
+ ffa_msg_send_direct_resp_64(msg->destination_id,
+ msg->source_id, SP_TEST_OK, 0, 0, 0, 0, msg);
+}
+
+static bool test_read_access(void)
+{
+ return (shared_buffer[0] != 5);
+
+}
+
+static void test_write_access(void)
+{
+ shared_buffer[0] = 0xff;
+}
+
+static void test_increase(struct ffa_direct_msg *msg)
+{
+ msg->args.args64[1]++;
+ msg->args.args64[2]++;
+ msg->args.args64[3]++;
+ msg->args.args64[4]++;
+ ffa_msg_send_direct_resp_64(msg->destination_id,msg->source_id,
+ SP_TEST_OK, msg->args.args64[1],
+ msg->args.args64[2],msg->args.args64[3],
+ msg->args.args64[4], msg);
+
+}
+
+static void test_communication(struct ffa_direct_msg *msg)
+{
+ struct ffa_direct_msg sp_msg = {0};
+ uint16_t caller = msg->source_id;
+ uint16_t src = msg->destination_id;
+ uint16_t dst = (uint16_t)msg->args.args64[1];
+ ffa_result res = FFA_OK;
+ struct ffa_params raw_params = { 0 };
+
+ sp_msg.args.args64[1] = 0x55;
+ sp_msg.args.args64[2] = 0xAA;
+ sp_msg.args.args64[3] = 0xBB;
+ sp_msg.args.args64[4] = 0xCC;
+
+ res = ffa_msg_send_direct_req_64(src, dst,
+ EP_TEST_SP_INCREASE,0x55, 0xAA, 0xBB,
+ 0xCC, &sp_msg);
+ if (res != FFA_OK) {
+ EMSG("error % in %s:%d"PRId32, res, __FILE__, __LINE__);
+ goto err;
+ }
+
+ if (sp_msg.args.args64[1] != 0x56 || sp_msg.args.args64[2] != 0xAB ||
+ sp_msg.args.args64[3] != 0xBC || sp_msg.args.args64[4] != 0xCD) {
+ DMSG("Failed SP communication %lx %lx %lx %lx",
+ sp_msg.args.args64[1], sp_msg.args.args64[2],
+ sp_msg.args.args64[3], sp_msg.args.args64[4]);
+ goto err;
+ }
+
+ /* Non-null flags (W2) register */
+ ffa_svc(FFA_MSG_SEND_DIRECT_REQ_64, (uint32_t)(src << 16 | 0x1000), 1, 0, 0, 0, 0, 0,
+ &raw_params);
+ if (raw_params.a0 != FFA_ERROR || (uint32_t)raw_params.a2 != FFA_INVALID_PARAMETERS) {
+ EMSG("Unexpected error code: %d != %ld", FFA_INVALID_PARAMETERS, raw_params.a2);
+ goto err;
+ }
+
+ /* Testing non-matching source ID */
+ res = ffa_msg_send_direct_req_64(src + 1, dst, 0, 0, 0, 0, 0, &sp_msg);
+ if (res != FFA_INVALID_PARAMETERS) {
+ EMSG("Unexpected error code: %d != %d", FFA_INVALID_PARAMETERS, res);
+ goto err;
+ }
+
+ /* Sending message to own ID */
+ res = ffa_msg_send_direct_req_64(src, src, 0, 0, 0, 0, 0, &sp_msg);
+ if (res != FFA_INVALID_PARAMETERS) {
+ EMSG("Unexpected error code: %d != %d", FFA_INVALID_PARAMETERS, res);
+ goto err;
+ }
+
+ /* Sending message to normal world */
+ res = ffa_msg_send_direct_req_64(src, 0, 0, 0, 0, 0, 0, &sp_msg);
+ if (res != FFA_NOT_SUPPORTED) {
+ EMSG("Unexpected error code: %d != %d", FFA_NOT_SUPPORTED, res);
+ goto err;
+ }
+
+ /* Sending message for starting direct message response test */
+ if (!caller) {
+ res = ffa_msg_send_direct_req_64(src, dst, EP_TEST_SP_COMMUNICATION_RESPONSE, 0, 0,
+ 0, 0, &sp_msg);
+ if (res != FFA_OK) {
+ EMSG("Unexpected error code: %d != %d", FFA_OK, res);
+ goto err;
+ }
+
+ if (sp_msg.args.args64[0] != SP_TEST_OK) {
+ EMSG("Unexpected test result: %d != %ld", SP_TEST_OK, sp_msg.args.args64[0]);
+ goto err;
+ }
+ }
+
+ return_ok(msg);
+ return;
+
+err:
+ return_error(ERR_SP_COMMUNICATION, msg);
+}
+
+static void test_communication_response(struct ffa_direct_msg *msg)
+{
+ struct ffa_direct_msg sp_msg = {0};
+ uint16_t caller = msg->source_id;
+ uint16_t src = msg->destination_id;
+ ffa_result res = FFA_OK;
+ struct ffa_params raw_params = { 0 };
+
+ /* Non-null flags (W2) register */
+ ffa_svc(FFA_MSG_SEND_DIRECT_RESP_64, (uint32_t)(src << 16 | 0x1000), 1, 0, 0, 0, 0, 1,
+ &raw_params);
+ if (raw_params.a0 != FFA_ERROR || (uint32_t)raw_params.a2 != FFA_INVALID_PARAMETERS) {
+ EMSG("Unexpected error code: %d != %ld", FFA_INVALID_PARAMETERS, raw_params.a2);
+ goto err;
+ }
+
+ /* Testing non-matching source ID */
+ res = ffa_msg_send_direct_resp_64(src + 1, caller, 0, 0, 0, 0, 2, &sp_msg);
+ if (res != FFA_INVALID_PARAMETERS) {
+ EMSG("Unexpected error code: %d != %d", FFA_INVALID_PARAMETERS, res);
+ goto err;
+ }
+
+ /* Sending message to own ID */
+ res = ffa_msg_send_direct_resp_64(src, src, 0, 0, 0, 0, 3, &sp_msg);
+ if (res != FFA_INVALID_PARAMETERS) {
+ EMSG("Unexpected error code: %d != %d", FFA_INVALID_PARAMETERS, res);
+ goto err;
+ }
+
+ /* Sending message request to caller SP which is busy */
+ if (caller) {
+ /* Sending message to normal world */
+ res = ffa_msg_send_direct_resp_64(src, 0, 0, 0, 0, 0, 4, &sp_msg);
+ if (res != FFA_INVALID_PARAMETERS) {
+ EMSG("Unexpected error code: %d != %d", FFA_INVALID_PARAMETERS, res);
+ goto err;
+ }
+
+ /* Sending message to invalid SP */
+ res = ffa_msg_send_direct_resp_64(src, 0x1000, 0, 0, 0, 0, 5, &sp_msg);
+ if (res != FFA_INVALID_PARAMETERS) {
+ EMSG("Unexpected error code: %d != %d", FFA_INVALID_PARAMETERS, res);
+ goto err;
+ }
+
+ /* Sending message request to caller SP which is busy */
+ res = ffa_msg_send_direct_req_64(src, caller, 0, 0, 0, 0, 6, &sp_msg);
+ if (res != FFA_BUSY) {
+ EMSG("Unexpected error code: %d != %d", FFA_BUSY, res);
+ goto err;
+ }
+ }
+
+ ffa_msg_send_direct_resp_64(src, caller, SP_TEST_OK, 0, 0, 0, 0, msg);
+ return;
+
+err:
+ ffa_msg_send_direct_resp_64(src, caller, ERR_SP_COMMUNICATION, 0, 0, 0, 0, msg);
+
+}
+
+static void test_internal_sp(struct ffa_direct_msg *msg)
+{
+ enum errors err = ERR_OK;
+ uint16_t id = 0;
+
+ if (test_ffa_version()) {
+ if (!test_ffa_id_get(&id))
+ err = ERR_ID_GET;
+
+ if (!err && !test_ffa_features())
+ err = ERR_VERSION;
+
+ if (!err && !test_ffa_rxtx_unmap(id))
+ err = ERR_RXTX_UNMAP;
+
+ if (!err && !test_ffa_rxtx_map())
+ err = ERR_RXTX_MAP;
+
+ if (!err && !test_ffa_partition_info_get())
+ err = ERR_PARTITION;
+
+ } else {
+ err = ERR_VERSION;
+ }
+
+ if (err != ERR_OK) {
+ DMSG("Failed at SP test %x", err);
+ return_error((uint32_t)err, msg);
+ }
+
+ return_ok(msg);
+}
+
+static void set_rxtx_buf(struct ffa_mem_transaction_buffer *t_buf,
+ struct ffa_mem_transaction_buffer *r_buf)
+{
+ if (t_buf) {
+ t_buf->buffer = (void*)tx_buffer;
+ t_buf->length = 4096;
+ t_buf->used = false;
+ }
+ if (r_buf) {
+ r_buf->buffer = (void*)rx_buffer;
+ r_buf->length = 4096;
+ r_buf->used = false;
+ }
+}
+
+static void test_mem_retrieve(struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor descriptor = {0};
+ struct sp_memory_region regions[1] = {0};
+ struct sp_memory_access_descriptor acc_desc = {0};
+ uint64_t handle = 0;
+ uint32_t out_region_count = 1;
+ uint16_t own_id = 0;
+
+ ffa_id_get(&own_id);
+
+ handle = (uint64_t)msg->args.args64[1] |
+ (((uint64_t)msg->args.args64[2]) << 32);
+ descriptor.tag = 0;
+ descriptor.sender_id = msg->args.args64[3] & 0xffff;
+ acc_desc.receiver_id = own_id;
+ acc_desc.data_access = sp_data_access_read_write;
+ res = sp_memory_retrieve(&descriptor, &acc_desc, regions, 1,
+ &out_region_count, handle);
+
+ if (res) {
+ DMSG("Failed retrieving me share");
+ return_error((uint32_t)ERR_MEM_RETRIEVE, msg);
+ return;
+ }
+
+ shared_buffer = regions[0].address;
+ shared_buffer_size = regions[0].page_count * 4096;
+
+ return_ok(msg);
+}
+
+static void test_mem_relinquish(struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ uint64_t handle = 0;
+ uint16_t endpoint_id = 0;
+ struct sp_memory_transaction_flags flags = {
+ .zero_memory = false,
+ .operation_time_slicing = false,
+ };
+
+ if (msg->args.args64[3] == 1)
+ flags.zero_memory = true;
+
+ ffa_id_get(&endpoint_id);
+ handle = (uint64_t)msg->args.args64[1] |
+ (((uint64_t)msg->args.args64[2]) << 32);
+
+ res = sp_memory_relinquish(handle, &endpoint_id, 1, &flags);
+ if (res) {
+ DMSG("Failed to relinquish share");
+ return_error((uint32_t)ERR_MEM_RELINQUISH, msg);
+ }
+
+ return_ok(msg);
+}
+
+static void test_mem_sharing(uint16_t service_ep_id, struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint64_t handle = 0;
+ struct ffa_mem_transaction_buffer t_buf = {0};
+ uint16_t own_id = 0;
+ uint16_t src_id = msg->source_id;
+ struct sp_memory_access_descriptor acc_desc = { };
+
+ my_buf[0] = 0xa;
+ set_rxtx_buf(&t_buf, NULL);
+ ffa_id_get(&own_id);
+
+ region.address = (void*) my_buf;
+ region.page_count = 1;
+ desc.sender_id = own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability =
+ sp_cacheability_write_back;
+
+ desc.mem_region_attr.normal_memory.shareability =
+ sp_shareability_inner_shareable;
+
+ acc_desc.data_access = sp_data_access_read_write;
+ acc_desc.instruction_access = sp_instruction_access_not_executable;
+ acc_desc.receiver_id = service_ep_id;
+
+ res = sp_memory_share(&desc, &acc_desc, 1, &region, 1, &handle);
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req_64(own_id, service_ep_id,
+ EP_RETRIEVE, handle & 0xffffffff,
+ handle >> 32, own_id, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req_64(own_id, service_ep_id,
+ EP_TRY_W_ACCESS, 0,
+ 0, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req_64(own_id, service_ep_id,
+ EP_RELINQUISH, handle & 0xffffffff,
+ handle >> 32, 0, 0, msg);
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_mem_reclaim(handle, 0);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+
+ return_ok(msg);
+}
+
+static void test_mem_multi_sharing(struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint64_t handle = 0;
+ struct ffa_mem_transaction_buffer t_buf = {0};
+ uint16_t own_id = 0;
+ uint16_t src_id = msg->source_id = 0;
+ struct sp_memory_access_descriptor acc_desc[2] = { };
+ uint32_t err = 0;
+ uint16_t endpoint2 = msg->args.args64[1];
+ uint16_t endpoint3 = msg->args.args64[2];
+
+ my_buf[0] = 0xa;
+ set_rxtx_buf(&t_buf, NULL);
+ ffa_id_get(&own_id);
+
+ region.address = (void*) my_buf;
+ region.page_count = 1;
+ desc.sender_id = own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability =
+ sp_cacheability_write_back;
+
+ desc.mem_region_attr.normal_memory.shareability =
+ sp_shareability_inner_shareable;
+
+ acc_desc[0].data_access = sp_data_access_read_write;
+ acc_desc[0].instruction_access = sp_instruction_access_not_executable;
+ acc_desc[0].receiver_id = endpoint2;
+
+ acc_desc[1].data_access = sp_data_access_read_write;
+ acc_desc[1].instruction_access = sp_instruction_access_not_executable;
+ acc_desc[1].receiver_id = endpoint3;
+
+ res = sp_memory_share(&desc, acc_desc, 2, &region, 1, &handle);
+ if (res != FFA_OK) {
+ EMSG("ffa_memory_share(): error %"PRId32, res);
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+ /* test SP2*/
+ res = ffa_msg_send_direct_req_64(own_id, endpoint2,
+ EP_RETRIEVE, handle & 0xffffffff,
+ handle >> 32, own_id, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req_64(own_id, endpoint2,
+ EP_TRY_W_ACCESS, 0,
+ 0, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ if (my_buf[0] != 0xff) {
+ EMSG("SP2 didn't change the value of the buffer");
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+
+ res = ffa_msg_send_direct_req_64(own_id, endpoint2,
+ EP_RELINQUISH, handle & 0xffffffff,
+ handle >> 32, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+ my_buf[0] = 0xa;
+ /* test SP3*/
+ res = ffa_msg_send_direct_req_64(own_id, endpoint3,
+ EP_RETRIEVE, handle & 0xffffffff,
+ handle >> 32, own_id, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req_64(own_id, endpoint3,
+ EP_TRY_W_ACCESS, 0,
+ 0, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ if (my_buf[0] != 0xff) {
+ EMSG("SP3 didn't change the value of the buffer");
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+
+ if (ffa_mem_reclaim(handle, 0) == FFA_OK) {
+ EMSG("SP3 didn't relinquish memory yet!");
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+
+ res = ffa_msg_send_direct_req_64(own_id, endpoint3,
+ EP_RELINQUISH, handle & 0xffffffff,
+ handle >> 32, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ if (ffa_mem_reclaim(handle, 0) != FFA_OK) {
+ EMSG("All memory should have been relinquished!");
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_ok(msg);
+ return;
+err:
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_error(err, msg);
+}
+
+static void test_mem_sharing_inccorrect_access(uint16_t service_ep_id,
+ struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint64_t handle = 0;
+ struct ffa_mem_transaction_buffer t_buf = {0};
+ uint16_t own_id = 0;
+ uint16_t src_id = msg->source_id = 0;
+ struct sp_memory_access_descriptor acc_desc = { };
+
+ set_rxtx_buf(&t_buf, NULL);
+ ffa_id_get(&own_id);
+
+ region.address = (void*) my_buf;
+ region.page_count = 1;
+ desc.sender_id = own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability =
+ sp_cacheability_write_back;
+
+ desc.mem_region_attr.normal_memory.shareability =
+ sp_shareability_inner_shareable;
+
+ acc_desc.data_access = sp_data_access_read_write;
+ acc_desc.instruction_access = sp_instruction_access_executable;
+ acc_desc.receiver_id = service_ep_id;
+
+ res = sp_memory_share(&desc, &acc_desc, 1, &region, 1, &handle);
+ if (res == FFA_OK) {
+ EMSG("ffa_memory_share(): error %"PRId32, res);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_ok(msg);
+}
+
+static void test_mem_sharing_exc(uint16_t service_ep_id,
+ struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint64_t handle = 0;
+ uint64_t handle2 = 0;
+ struct ffa_mem_transaction_buffer t_buf = {0};
+ uint16_t own_id = 0;
+ uint16_t src_id = msg->source_id = 0;
+ struct sp_memory_access_descriptor acc_desc = { };
+ uint32_t err = 0;
+
+ set_rxtx_buf(&t_buf, NULL);
+ ffa_id_get(&own_id);
+
+ region.address = (void*) my_buf;
+ region.page_count = 1;
+ desc.sender_id = own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability =
+ sp_cacheability_write_back;
+
+ desc.mem_region_attr.normal_memory.shareability =
+ sp_shareability_inner_shareable;
+
+ acc_desc.data_access = sp_data_access_read_write;
+ acc_desc.instruction_access = sp_instruction_access_not_executable;
+ acc_desc.receiver_id = service_ep_id;
+
+ res = sp_memory_share(&desc, &acc_desc, 1, &region, 1, &handle);
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing_exc(): error %"PRId32, res);
+ err = (uint32_t)ERR_SP_SHARE_EXC;
+ goto err;
+ }
+
+ /*
+ * Try it again, it should fail as we don't have acclusive access
+ * anymore
+ */
+ res = sp_memory_share(&desc, &acc_desc, 1, &region, 1, &handle2);
+ if (res == FFA_OK) {
+ EMSG("test_mem_sharing_exc(): error %"PRId32, res);
+ err = (uint32_t)ERR_SP_SHARE_EXC;
+ goto err;
+ }
+
+ res = ffa_mem_reclaim(handle, 0);
+
+ if (res != FFA_OK) {
+ EMSG("ffa_memory_share(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_ok(msg);
+ return;
+err:
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_error(err, msg);
+}
+
+void test_mem_get_set(union ffa_boot_info *boot_info)
+{
+ void *addr = NULL;
+ ffa_result res = FFA_OK;
+ struct memory_region buffer_region = { 0 };
+ uint32_t mem_perm = 0;
+ const uint32_t original_perm = FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_NX |
+ FFA_MEM_PERM_DATA_ACCESS_PERM_RW;
+ const uint32_t ro_perm = FFA_MEM_PERM_INSTRUCTION_ACCESS_PERM_NX |
+ FFA_MEM_PERM_DATA_ACCESS_PERM_RO;
+
+ DMSG("Testing FFA_MEM_PERM_GET/SET");
+ config_ramstore_init();
+
+ if (!sp_config_load(boot_info)) {
+ EMSG("Failed to load SP config");
+ goto err;
+ }
+
+ /* Only run the test if we have the test-region enabled */
+ if (!config_store_query(CONFIG_CLASSIFIER_MEMORY_REGION, "test-region",
+ 0, &buffer_region, sizeof(buffer_region)))
+ return;
+
+ addr = (void *)buffer_region.base_addr;
+ /* Check original permissions */
+ res = ffa_mem_perm_get(addr, &mem_perm);
+ if (res)
+ goto err;
+
+ if (mem_perm != original_perm) {
+ EMSG("Incorrect permision got 0x%x expected 0x%x", mem_perm, original_perm);
+ res = FFA_INVALID_PARAMETERS;
+ goto err;
+ }
+
+ /* Remove write permission */
+ res = ffa_mem_perm_set(addr, 1, ro_perm);
+ if (res)
+ goto err;
+
+ /* Check if write permission is removed */
+ res = ffa_mem_perm_get(addr, &mem_perm);
+ if (res)
+ goto err;
+
+ if (mem_perm != ro_perm) {
+ EMSG("Incorrect permision got 0x%x expected 0x%x", mem_perm, original_perm);
+ res = FFA_INVALID_PARAMETERS;
+ goto err;
+ }
+ /* Set write permission back */
+ res = ffa_mem_perm_set(addr, 1, original_perm);
+ if (res)
+ goto err;
+
+ /* Check original permissions */
+ res = ffa_mem_perm_get(addr, &mem_perm);
+ if (res)
+ goto err;
+
+ if (mem_perm != original_perm) {
+ EMSG("Incorrect permision got 0x%x expected 0x%x", mem_perm, original_perm);
+ res = FFA_INVALID_PARAMETERS;
+ goto err;
+ }
+
+ return;
+err:
+ EMSG("GET/SET_MEM failed (0x%x)", res);
+}
+
+void __noreturn sp_main(union ffa_boot_info *boot_info) {
+ struct ffa_direct_msg msg = {0};
+ uint16_t own_id = 0;
+
+ /* Boot phase */
+ if (sp_discovery_own_id_get(&own_id) != SP_RESULT_OK) {
+ EMSG("Couldn't get own_id!!");
+ }
+
+ test_ffa_rxtx_map();
+ test_mem_get_set(boot_info);
+ /* End of boot phase */
+ test_ffa_partition_info_get();
+ ffa_msg_wait(&msg);
+
+ while (1) {
+ enum sp_tests test_case = (enum sp_tests)msg.args.args64[0];
+
+ DMSG("SP:%x Starting test %s", own_id, sp_test_str[test_case]);
+ switch (test_case) {
+ case EP_TEST_SP:
+ test_internal_sp(&msg);
+ break;
+ case EP_TEST_SP_COMMUNICATION:
+ test_communication(&msg);
+ break;
+ case EP_TEST_SP_COMMUNICATION_RESPONSE:
+ test_communication_response(&msg);
+ break;
+ case EP_TEST_SP_INCREASE:
+ test_increase(&msg);
+ break;
+ case EP_TRY_R_ACCESS:
+ test_read_access();
+ return_ok(&msg);
+ break;
+ case EP_TRY_W_ACCESS:
+ test_write_access();
+ return_ok(&msg);
+ break;
+ case EP_RETRIEVE:
+ test_mem_retrieve(&msg);
+ break;
+ case EP_RELINQUISH:
+ test_mem_relinquish(&msg);
+ break;
+ case EP_SP_MEM_SHARING:
+ test_mem_sharing((uint16_t)msg.args.args64[1], &msg);
+ break;
+ case EP_SP_MEM_SHARING_MULTI:
+ test_mem_multi_sharing(&msg);
+ break;
+ case EP_SP_MEM_SHARING_EXC:
+ test_mem_sharing_exc((uint16_t)msg.args.args64[1],
+ &msg);
+ break;
+ case EP_SP_MEM_INCORRECT_ACCESS:
+ test_mem_sharing_inccorrect_access(
+ (uint16_t)msg.args.args64[1], &msg);
+ break;
+ case EP_SP_NOP:
+ return_ok(&msg);
+ break;
+
+ default:
+ return_error((uint32_t)ERR_TEST_NOT_FOUND, &msg);
+ break;
+ }
+ }
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+ DMSG("Got interrupt %x", interrupt_id);
+}
diff --git a/components/service/spm_test/spm_test.cmake b/components/service/spm_test/spm_test.cmake
new file mode 100644
index 000000000..e8a1ccd48
--- /dev/null
+++ b/components/service/spm_test/spm_test.cmake
@@ -0,0 +1,73 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the spm-test sp deployment for opteesp
+#
+# Used for building the SPs used in the spm test. The SP can be build twice
+# , to be able to test inter SPs communication. This is done by passing the
+# -DSP_NUMBER=1 parameter.
+#-------------------------------------------------------------------------------
+target_include_directories(spm-test${SP_NUMBER} PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+#-------------------------------------------------------------------------------
+# Extend with components that are common across all deployments of
+# spm-test
+#
+#-------------------------------------------------------------------------------
+target_include_directories(spm-test${SP_NUMBER} PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET spm-test${SP_NUMBER})
+
+#################################################################
+
+target_compile_definitions(spm-test${SP_NUMBER} PRIVATE
+ ARM64=1
+)
+
+target_include_directories(spm-test${SP_NUMBER} PRIVATE
+ ${TS_ROOT}/components/service/spm_test
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(spm-test${SP_NUMBER} PRIVATE
+ -std=c99
+ )
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific source files
+#-------------------------------------------------------------------------------
+target_sources(spm-test${SP_NUMBER} PRIVATE
+ ${TS_ROOT}/components/service/spm_test/sp.c
+)
+
+######################################## install
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+
+install(TARGETS spm-test${SP_NUMBER}
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "spm-test${SP_NUMBER}"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${TS_ROOT}/deployments/spm-test${SP_NUMBER}/opteesp/default_spm_test${SP_NUMBER}.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/components/service/test_runner/client/cpp/test_runner_client.cpp b/components/service/test_runner/client/cpp/test_runner_client.cpp
index 9d9a20db0..31df93dcd 100644
--- a/components/service/test_runner/client/cpp/test_runner_client.cpp
+++ b/components/service/test_runner/client/cpp/test_runner_client.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,10 +22,10 @@ test_runner_client::test_runner_client() :
service_client_init(&m_client, NULL);
}
-test_runner_client::test_runner_client(struct rpc_caller *caller) :
+test_runner_client::test_runner_client(struct rpc_caller_session *session) :
m_client()
{
- service_client_init(&m_client, caller);
+ service_client_init(&m_client, session);
}
test_runner_client::~test_runner_client()
@@ -33,9 +33,9 @@ test_runner_client::~test_runner_client()
service_client_deinit(&m_client);
}
-void test_runner_client::set_caller(struct rpc_caller *caller)
+void test_runner_client::set_caller(struct rpc_caller_session *session)
{
- m_client.caller = caller;
+ m_client.session = session;
}
int test_runner_client::err_rpc_status() const
@@ -65,7 +65,7 @@ int test_runner_client::iterate_over_tests(
std::vector<struct test_result> &results)
{
int test_status = TS_TEST_RUNNER_STATUS_ERROR;
- m_client.rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+ m_client.rpc_status = RPC_ERROR_RESOURCE_FAILURE;
rpc_call_handle call_handle;
uint8_t *req_buf;
std::vector<uint8_t> req_param;
@@ -73,13 +73,14 @@ int test_runner_client::iterate_over_tests(
serialize_test_spec(req_param, spec);
size_t req_len = req_param.size();
- call_handle = rpc_caller_begin(m_client.caller, &req_buf, req_len);
+ size_t resp_len = 1024;
+ call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len, resp_len);
if (call_handle) {
uint8_t *resp_buf;
size_t resp_len;
- rpc_opstatus_t opstatus;
+ service_status_t service_status;
memcpy(req_buf, req_param.data(), req_len);
@@ -87,20 +88,20 @@ int test_runner_client::iterate_over_tests(
TS_TEST_RUNNER_OPCODE_LIST_TESTS :
TS_TEST_RUNNER_OPCODE_RUN_TESTS;
- m_client.rpc_status = rpc_caller_invoke(m_client.caller, call_handle,
- opcode, &opstatus, &resp_buf, &resp_len);
+ m_client.rpc_status = rpc_caller_session_invoke(call_handle,
+ opcode, &resp_buf, &resp_len, &service_status);
if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
- test_status = opstatus;
+ test_status = service_status;
- if (opstatus == TS_TEST_RUNNER_STATUS_SUCCESS) {
+ if (test_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
test_status = deserialize_results(resp_buf, resp_len, summary, results);
}
}
- rpc_caller_end(m_client.caller, call_handle);
+ rpc_caller_session_end(call_handle);
}
return test_status;
@@ -208,10 +209,8 @@ int test_runner_client::deserialize_result(
struct ts_test_runner_test_result packed_result;
memcpy(&packed_result, value_buf, fixed_size);
+ memset(&result, 0, sizeof(result));
result.run_state = (enum test_run_state)packed_result.run_state;
- result.name[0] = 0;
- result.group[0] = 0;
- result.failure = {0};
/* Deserialize name and group if present */
struct tlv_const_iterator req_iter;
diff --git a/components/service/test_runner/client/cpp/test_runner_client.h b/components/service/test_runner/client/cpp/test_runner_client.h
index d3d39cefb..cdac87916 100644
--- a/components/service/test_runner/client/cpp/test_runner_client.h
+++ b/components/service/test_runner/client/cpp/test_runner_client.h
@@ -21,10 +21,10 @@ class test_runner_client
{
public:
test_runner_client();
- test_runner_client(struct rpc_caller *caller);
+ test_runner_client(struct rpc_caller_session *session);
virtual ~test_runner_client();
- void set_caller(struct rpc_caller *caller);
+ void set_caller(struct rpc_caller_session *session);
int err_rpc_status() const;
int run_tests(const struct test_spec &spec,
diff --git a/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c b/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c
index fb66d752d..27a22cb9d 100644
--- a/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c
+++ b/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -123,7 +123,7 @@ static size_t count_tests(const struct test_spec *spec)
{
size_t count = 0;
- for (int group_index = 0; group_index < the_test_runner.num_groups; ++group_index) {
+ for (size_t group_index = 0; group_index < the_test_runner.num_groups; ++group_index) {
count += the_test_runner.groups[group_index]->num_test_cases;
}
@@ -141,4 +141,4 @@ static void list_tests(const struct test_spec *spec,
struct test_summary *summary, struct test_result *results, size_t result_limit)
{
test_iterate(spec, true, summary, results, result_limit);
-} \ No newline at end of file
+}
diff --git a/components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c b/components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c
index 5892502b5..74fdd6606 100644
--- a/components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c
+++ b/components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c
@@ -1,204 +1,202 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
+#include "packedc_test_runner_provider_serializer.h"
+
#include <common/tlv/tlv.h>
#include <protocols/rpc/common/packed-c/status.h>
-#include <protocols/service/test_runner/packed-c/run_tests.h>
#include <protocols/service/test_runner/packed-c/list_tests.h>
-#include "packedc_test_runner_provider_serializer.h"
+#include <protocols/service/test_runner/packed-c/run_tests.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
/* Common rerialization methods used for different operations */
-static rpc_status_t deserialize_test_spec(const struct call_param_buf *req_buf,
- struct test_spec *test_spec)
+static rpc_status_t deserialize_test_spec(const struct rpc_buffer *req_buf,
+ struct test_spec *test_spec)
{
- struct tlv_const_iterator req_iter;
- struct tlv_record decoded_record;
-
- test_spec->name[0] = 0;
- test_spec->group[0] = 0;
-
- tlv_const_iterator_begin(&req_iter, (uint8_t*)req_buf->data, req_buf->data_len);
-
- if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_SPEC_TAG_NAME, &decoded_record)) {
+ struct tlv_const_iterator req_iter;
+ struct tlv_record decoded_record;
- if ((decoded_record.length > 0) && (decoded_record.length < TEST_NAME_MAX_LEN)) {
+ test_spec->name[0] = 0;
+ test_spec->group[0] = 0;
- memcpy(test_spec->name, decoded_record.value, decoded_record.length);
- test_spec->name[decoded_record.length] = 0;
- }
- }
+ tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data, req_buf->data_length);
- if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_SPEC_TAG_GROUP, &decoded_record)) {
+ if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_SPEC_TAG_NAME, &decoded_record)) {
+ if ((decoded_record.length > 0) && (decoded_record.length < TEST_NAME_MAX_LEN)) {
+ memcpy(test_spec->name, decoded_record.value, decoded_record.length);
+ test_spec->name[decoded_record.length] = 0;
+ }
+ }
- if ((decoded_record.length > 0) && (decoded_record.length < TEST_GROUP_MAX_LEN)) {
+ if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_SPEC_TAG_GROUP, &decoded_record)) {
+ if ((decoded_record.length > 0) && (decoded_record.length < TEST_GROUP_MAX_LEN)) {
+ memcpy(test_spec->group, decoded_record.value, decoded_record.length);
+ test_spec->group[decoded_record.length] = 0;
+ }
+ }
- memcpy(test_spec->group, decoded_record.value, decoded_record.length);
- test_spec->group[decoded_record.length] = 0;
- }
- }
-
- return TS_RPC_CALL_ACCEPTED;
+ return TS_RPC_CALL_ACCEPTED;
}
static uint8_t *serialize_test_result(const struct test_result *result, size_t *serialized_len)
{
- uint8_t *out_buf;
- size_t fixed_len = sizeof(struct ts_test_runner_test_result);
- size_t required_space = fixed_len;
- size_t name_len = strlen(result->name);
- size_t group_len = strlen(result->group);
+ uint8_t *out_buf;
+ size_t fixed_len = sizeof(struct ts_test_runner_test_result);
+ size_t required_space = fixed_len;
+ size_t name_len = strlen(result->name);
+ size_t group_len = strlen(result->group);
- if (name_len) required_space += tlv_required_space(name_len);
- if (group_len) required_space += tlv_required_space(group_len);
- if (result->run_state == TEST_RUN_STATE_FAILED)
- required_space += tlv_required_space(sizeof(struct ts_test_runner_test_failure));
+ if (name_len)
+ required_space += tlv_required_space(name_len);
+ if (group_len)
+ required_space += tlv_required_space(group_len);
+ if (result->run_state == TEST_RUN_STATE_FAILED)
+ required_space += tlv_required_space(sizeof(struct ts_test_runner_test_failure));
- *serialized_len = required_space;
+ *serialized_len = required_space;
- out_buf = malloc(required_space);
+ out_buf = malloc(required_space);
- if (out_buf) {
+ if (out_buf) {
+ struct ts_test_runner_test_result result_msg;
+ struct tlv_iterator tlv_iter;
- struct ts_test_runner_test_result result_msg;
- result_msg.run_state = result->run_state;
+ result_msg.run_state = result->run_state;
- memcpy(out_buf, &result_msg, fixed_len);
+ memcpy(out_buf, &result_msg, fixed_len);
- struct tlv_iterator tlv_iter;
- tlv_iterator_begin(&tlv_iter, (uint8_t*)out_buf + fixed_len, required_space - fixed_len);
+ tlv_iterator_begin(&tlv_iter, (uint8_t *)out_buf + fixed_len,
+ required_space - fixed_len);
- if (name_len) {
+ if (name_len) {
+ struct tlv_record record;
- struct tlv_record record;
- record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_NAME;
- record.length = name_len;
- record.value = result->name;
- tlv_encode(&tlv_iter, &record);
- }
+ record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_NAME;
+ record.length = name_len;
+ record.value = (const uint8_t *)result->name;
+ tlv_encode(&tlv_iter, &record);
+ }
- if (group_len) {
+ if (group_len) {
+ struct tlv_record record;
- struct tlv_record record;
- record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_GROUP;
- record.length = group_len;
- record.value = result->group;
- tlv_encode(&tlv_iter, &record);
- }
+ record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_GROUP;
+ record.length = group_len;
+ record.value = (const uint8_t *)result->group;
+ tlv_encode(&tlv_iter, &record);
+ }
- if (result->run_state == TEST_RUN_STATE_FAILED) {
+ if (result->run_state == TEST_RUN_STATE_FAILED) {
+ struct ts_test_runner_test_failure serialized_failure;
+ struct tlv_record record;
- struct ts_test_runner_test_failure serialized_failure;
- serialized_failure.line_num = result->failure.line_num;
- serialized_failure.info = result->failure.info;
+ serialized_failure.line_num = result->failure.line_num;
+ serialized_failure.info = result->failure.info;
- struct tlv_record record;
- record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_FAILURE;
- record.length = sizeof(serialized_failure);
- record.value = (const uint8_t*)&serialized_failure;
- tlv_encode(&tlv_iter, &record);
- }
- }
+ record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_FAILURE;
+ record.length = sizeof(serialized_failure);
+ record.value = (const uint8_t *)&serialized_failure;
+ tlv_encode(&tlv_iter, &record);
+ }
+ }
- return out_buf;
+ return out_buf;
}
-static rpc_status_t serialize_test_results(struct call_param_buf *resp_buf,
- const struct test_summary *summary,
- const struct test_result *results)
+static rpc_status_t serialize_test_results(struct rpc_buffer *resp_buf,
+ const struct test_summary *summary,
+ const struct test_result *results)
{
- size_t space_used = 0;
- rpc_status_t rpc_status = TS_RPC_CALL_ACCEPTED;
-
- /* Serialize fixed size summary */
- struct ts_test_runner_result_summary summary_msg;
- size_t fixed_len = sizeof(struct ts_test_runner_result_summary);
+ size_t space_used = 0;
+ rpc_status_t rpc_status = TS_RPC_CALL_ACCEPTED;
- summary_msg.num_tests = summary->num_tests;
- summary_msg.num_passed = summary->num_passed;
- summary_msg.num_failed = summary->num_failed;
+ /* Serialize fixed size summary */
+ struct ts_test_runner_result_summary summary_msg;
+ size_t fixed_len = sizeof(struct ts_test_runner_result_summary);
- if (fixed_len + space_used <= resp_buf->size) {
+ summary_msg.num_tests = summary->num_tests;
+ summary_msg.num_passed = summary->num_passed;
+ summary_msg.num_failed = summary->num_failed;
- memcpy((uint8_t*)resp_buf->data + space_used, &summary_msg, fixed_len);
- space_used += fixed_len;
+ if (fixed_len + space_used <= resp_buf->size) {
+ memcpy((uint8_t *)resp_buf->data + space_used, &summary_msg, fixed_len);
+ space_used += fixed_len;
- /* Serialize test result objects */
- struct tlv_iterator resp_iter;
- tlv_iterator_begin(&resp_iter, (uint8_t*)resp_buf->data + space_used, resp_buf->size - space_used);
+ /* Serialize test result objects */
+ struct tlv_iterator resp_iter;
- for (int i = 0; (i < summary->num_results) && (rpc_status == TS_RPC_CALL_ACCEPTED); ++i) {
+ tlv_iterator_begin(&resp_iter, (uint8_t *)resp_buf->data + space_used,
+ resp_buf->size - space_used);
- size_t serialised_len;
- uint8_t *serialize_buf = serialize_test_result(&results[i], &serialised_len);
+ for (size_t i = 0;
+ (i < summary->num_results) && (rpc_status == TS_RPC_CALL_ACCEPTED); ++i) {
+ size_t serialised_len;
+ uint8_t *serialize_buf =
+ serialize_test_result(&results[i], &serialised_len);
- if (serialize_buf) {
+ if (serialize_buf) {
+ struct tlv_record result_record;
- struct tlv_record result_record;
- result_record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG;
- result_record.length = serialised_len;
- result_record.value = serialize_buf;
+ result_record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG;
+ result_record.length = serialised_len;
+ result_record.value = serialize_buf;
- if (tlv_encode(&resp_iter, &result_record)) {
+ if (tlv_encode(&resp_iter, &result_record)) {
+ space_used += tlv_required_space(serialised_len);
+ } else {
+ /* Insufficient buffer space */
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
+ }
- space_used += tlv_required_space(serialised_len);
- }
- else {
- /* Insufficient buffer space */
- rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
- }
+ free(serialize_buf);
+ }
+ }
+ }
- free(serialize_buf);
- }
- }
- }
+ resp_buf->data_length = space_used;
- resp_buf->data_len = space_used;
-
- return rpc_status;
+ return rpc_status;
}
/* Operation: run_tests */
-static rpc_status_t deserialize_run_tests_req(const struct call_param_buf *req_buf,
- struct test_spec *test_spec)
+static rpc_status_t deserialize_run_tests_req(const struct rpc_buffer *req_buf,
+ struct test_spec *test_spec)
{
- return deserialize_test_spec(req_buf, test_spec);
+ return deserialize_test_spec(req_buf, test_spec);
}
-static rpc_status_t serialize_run_tests_resp(struct call_param_buf *resp_buf,
- const struct test_summary *summary,
- const struct test_result *results)
+static rpc_status_t serialize_run_tests_resp(struct rpc_buffer *resp_buf,
+ const struct test_summary *summary,
+ const struct test_result *results)
{
- return serialize_test_results(resp_buf, summary, results);
+ return serialize_test_results(resp_buf, summary, results);
}
/* Operation: list_tests */
-static rpc_status_t deserialize_list_tests_req(const struct call_param_buf *req_buf,
- struct test_spec *test_spec)
+static rpc_status_t deserialize_list_tests_req(const struct rpc_buffer *req_buf,
+ struct test_spec *test_spec)
{
- return deserialize_test_spec(req_buf, test_spec);
+ return deserialize_test_spec(req_buf, test_spec);
}
-static rpc_status_t serialize_list_tests_resp(struct call_param_buf *resp_buf,
- const struct test_summary *summary,
- const struct test_result *results)
+static rpc_status_t serialize_list_tests_resp(struct rpc_buffer *resp_buf,
+ const struct test_summary *summary,
+ const struct test_result *results)
{
- return serialize_test_results(resp_buf, summary, results);
+ return serialize_test_results(resp_buf, summary, results);
}
/* Singleton method to provide access to the serializer instance */
const struct test_runner_provider_serializer *packedc_test_runner_provider_serializer_instance(void)
{
- static const struct test_runner_provider_serializer instance = {
- deserialize_run_tests_req,
- serialize_run_tests_resp,
- deserialize_list_tests_req,
- serialize_list_tests_resp
- };
-
- return &instance;
+ static const struct test_runner_provider_serializer instance = {
+ deserialize_run_tests_req, serialize_run_tests_resp, deserialize_list_tests_req,
+ serialize_list_tests_resp
+ };
+
+ return &instance;
}
diff --git a/components/service/test_runner/provider/serializer/test_runner_provider_serializer.h b/components/service/test_runner/provider/serializer/test_runner_provider_serializer.h
index bd457f77b..4999a1e58 100644
--- a/components/service/test_runner/provider/serializer/test_runner_provider_serializer.h
+++ b/components/service/test_runner/provider/serializer/test_runner_provider_serializer.h
@@ -7,7 +7,7 @@
#ifndef TEST_RUNNER_PROVIDER_SERIALIZER_H
#define TEST_RUNNER_PROVIDER_SERIALIZER_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "rpc/common/endpoint/rpc_service_interface.h"
#include <service/test_runner/common/test_runner.h>
/* Provides a common interface for parameter serialization operations
@@ -18,21 +18,21 @@
*/
struct test_runner_provider_serializer {
- /* Operation: run_tests */
- rpc_status_t (*deserialize_run_tests_req)(const struct call_param_buf *req_buf,
- struct test_spec *test_spec);
+ /* Operation: run_tests */
+ rpc_status_t (*deserialize_run_tests_req)(const struct rpc_buffer *req_buf,
+ struct test_spec *test_spec);
- rpc_status_t (*serialize_run_tests_resp)(struct call_param_buf *resp_buf,
- const struct test_summary *summary,
- const struct test_result *results);
+ rpc_status_t (*serialize_run_tests_resp)(struct rpc_buffer *resp_buf,
+ const struct test_summary *summary,
+ const struct test_result *results);
- /* Operation: list_tests */
- rpc_status_t (*deserialize_list_tests_req)(const struct call_param_buf *req_buf,
- struct test_spec *test_spec);
+ /* Operation: list_tests */
+ rpc_status_t (*deserialize_list_tests_req)(const struct rpc_buffer *req_buf,
+ struct test_spec *test_spec);
- rpc_status_t (*serialize_list_tests_resp)(struct call_param_buf *resp_buf,
- const struct test_summary *summary,
- const struct test_result *results);
+ rpc_status_t (*serialize_list_tests_resp)(struct rpc_buffer *resp_buf,
+ const struct test_summary *summary,
+ const struct test_result *results);
};
#endif /* TEST_RUNNER_PROVIDER_SERIALIZER_H */
diff --git a/components/service/test_runner/provider/test_runner_provider.c b/components/service/test_runner/provider/test_runner_provider.c
index 4b61bc1d7..47ff9e83d 100644
--- a/components/service/test_runner/provider/test_runner_provider.c
+++ b/components/service/test_runner/provider/test_runner_provider.c
@@ -1,205 +1,205 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <stdlib.h>
-#include <stdbool.h>
+#include "test_runner_provider.h"
+
+#include <protocols/rpc/common/packed-c/status.h>
#include <protocols/service/test_runner/packed-c/opcodes.h>
#include <protocols/service/test_runner/packed-c/status.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include "test_runner_provider.h"
+#include <stdbool.h>
+#include <stdlib.h>
+
#include "test_runner_backend.h"
+#include "test_runner_uuid.h"
/* Service request handlers */
-static rpc_status_t run_tests_handler(void *context, struct call_req* req);
-static rpc_status_t list_tests_handler(void *context, struct call_req* req);
+static rpc_status_t run_tests_handler(void *context, struct rpc_request *req);
+static rpc_status_t list_tests_handler(void *context, struct rpc_request *req);
/* Handler mapping table for service */
static const struct service_handler handler_table[] = {
- {TS_TEST_RUNNER_OPCODE_RUN_TESTS, run_tests_handler},
- {TS_TEST_RUNNER_OPCODE_LIST_TESTS, list_tests_handler}
+ { TS_TEST_RUNNER_OPCODE_RUN_TESTS, run_tests_handler },
+ { TS_TEST_RUNNER_OPCODE_LIST_TESTS, list_tests_handler }
};
-struct rpc_interface *test_runner_provider_init(struct test_runner_provider *context)
+struct rpc_service_interface *test_runner_provider_init(struct test_runner_provider *context)
{
- struct rpc_interface *rpc_interface = NULL;
+ struct rpc_service_interface *rpc_interface = NULL;
+ const struct rpc_uuid service_uuid = { .uuid = TS_TEST_RUNNER_SERVICE_UUID };
- if (context) {
+ if (context) {
+ for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
+ context->serializers[encoding] = NULL;
- for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
- context->serializers[encoding] = NULL;
+ context->backend_list = NULL;
- context->backend_list = NULL;
+ service_provider_init(&context->base_provider, context, &service_uuid,
+ handler_table,
+ sizeof(handler_table) / sizeof(struct service_handler));
- service_provider_init(&context->base_provider, context,
- handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+ rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
- rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+ /* Allow a deployment specific test_runner backend to be registrered */
+ test_runner_register_default_backend(context);
+ }
- /* Allow a deployment specific test_runner backend to be registrered */
- test_runner_register_default_backend(context);
- }
-
- return rpc_interface;
+ return rpc_interface;
}
void test_runner_provider_deinit(struct test_runner_provider *context)
{
- (void)context;
+ (void)context;
}
-void test_runner_provider_register_serializer(struct test_runner_provider *context,
- unsigned int encoding, const struct test_runner_provider_serializer *serializer)
+void test_runner_provider_register_serializer(
+ struct test_runner_provider *context, unsigned int encoding,
+ const struct test_runner_provider_serializer *serializer)
{
- if (encoding < TS_RPC_ENCODING_LIMIT)
- context->serializers[encoding] = serializer;
+ if (encoding < TS_RPC_ENCODING_LIMIT)
+ context->serializers[encoding] = serializer;
}
void test_runner_provider_register_backend(struct test_runner_provider *context,
- struct test_runner_backend *backend)
+ struct test_runner_backend *backend)
{
- /* Insert into list of backend test runners */
- backend->next = context->backend_list;
- context->backend_list = backend;
+ /* Insert into list of backend test runners */
+ backend->next = context->backend_list;
+ context->backend_list = backend;
}
-static const struct test_runner_provider_serializer* get_test_runner_serializer(
- struct test_runner_provider *context, const struct call_req *req)
+static const struct test_runner_provider_serializer *
+get_test_runner_serializer(struct test_runner_provider *context, const struct rpc_request *req)
{
- const struct test_runner_provider_serializer* serializer = NULL;
- unsigned int encoding = call_req_get_encoding(req);
+ const struct test_runner_provider_serializer *serializer = NULL;
+ unsigned int encoding = 0; /* Only one encoding is supported now */
- if (encoding < TS_RPC_ENCODING_LIMIT) serializer = context->serializers[encoding];
+ if (encoding < TS_RPC_ENCODING_LIMIT)
+ serializer = context->serializers[encoding];
- return serializer;
+ return serializer;
}
static struct test_result *alloc_result_buf(struct test_runner_provider *context,
- const struct test_spec *test_spec, size_t *result_limit)
+ const struct test_spec *test_spec, size_t *result_limit)
{
- struct test_result *space = NULL;
- size_t total_tests = 0;
- struct test_runner_backend *backend = context->backend_list;
-
- while (backend) {
+ struct test_result *space = NULL;
+ size_t total_tests = 0;
+ struct test_runner_backend *backend = context->backend_list;
- total_tests += backend->count_tests(test_spec);
- backend = backend->next;
- }
+ while (backend) {
+ total_tests += backend->count_tests(test_spec);
+ backend = backend->next;
+ }
- space = malloc(total_tests * sizeof(struct test_result));
+ space = malloc(total_tests * sizeof(struct test_result));
- *result_limit = total_tests;
- return space;
+ *result_limit = total_tests;
+ return space;
}
-static int run_qualifying_tests(struct test_runner_provider *context, bool list_only, const struct test_spec *spec,
- struct test_summary *summary, struct test_result *results, size_t result_limit)
+static int run_qualifying_tests(struct test_runner_provider *context, bool list_only,
+ const struct test_spec *spec, struct test_summary *summary,
+ struct test_result *results, size_t result_limit)
{
- int test_status = TS_TEST_RUNNER_STATUS_SUCCESS;
- size_t results_used = 0;
- struct test_runner_backend *backend = context->backend_list;
+ int test_status = TS_TEST_RUNNER_STATUS_SUCCESS;
+ struct test_runner_backend *backend = context->backend_list;
- summary->num_tests = 0;
+ summary->num_tests = 0;
summary->num_results = 0;
summary->num_passed = 0;
summary->num_failed = 0;
- while (backend && (test_status == TS_TEST_RUNNER_STATUS_SUCCESS)) {
-
- struct test_summary interim_summary;
-
- if (list_only) {
-
- backend->list_tests(spec, &interim_summary,
- &results[summary->num_results],
- result_limit - summary->num_results);
- }
- else {
+ while (backend && (test_status == TS_TEST_RUNNER_STATUS_SUCCESS)) {
+ struct test_summary interim_summary;
- test_status = backend->run_tests(spec, &interim_summary,
- &results[summary->num_results],
- result_limit - summary->num_results);
- }
+ if (list_only) {
+ backend->list_tests(spec, &interim_summary, &results[summary->num_results],
+ result_limit - summary->num_results);
+ } else {
+ test_status = backend->run_tests(spec, &interim_summary,
+ &results[summary->num_results],
+ result_limit - summary->num_results);
+ }
- summary->num_tests += interim_summary.num_tests;
- summary->num_results += interim_summary.num_results;
- summary->num_passed += interim_summary.num_passed;
- summary->num_failed += interim_summary.num_failed;
+ summary->num_tests += interim_summary.num_tests;
+ summary->num_results += interim_summary.num_results;
+ summary->num_passed += interim_summary.num_passed;
+ summary->num_failed += interim_summary.num_failed;
- backend = backend->next;
- }
+ backend = backend->next;
+ }
- return test_status;
+ return test_status;
}
-static rpc_status_t run_tests_handler(void *context, struct call_req* req)
+static rpc_status_t run_tests_handler(void *context, struct rpc_request *req)
{
- struct test_runner_provider *this_instance = (struct test_runner_provider*)context;
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct test_spec test_spec;
+ struct test_runner_provider *this_instance = (struct test_runner_provider *)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct test_spec test_spec;
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct test_runner_provider_serializer *serializer = get_test_runner_serializer(this_instance, req);
+ struct rpc_buffer *req_buf = &req->request;
+ const struct test_runner_provider_serializer *serializer =
+ get_test_runner_serializer(this_instance, req);
- if (serializer)
- rpc_status = serializer->deserialize_run_tests_req(req_buf, &test_spec);
+ if (serializer)
+ rpc_status = serializer->deserialize_run_tests_req(req_buf, &test_spec);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (rpc_status == RPC_SUCCESS) {
+ struct test_summary summary;
+ size_t result_limit = 0;
+ struct test_result *result_buf =
+ alloc_result_buf(this_instance, &test_spec, &result_limit);
- int test_status;
- struct test_summary summary;
- size_t result_limit = 0;
- struct test_result *result_buf = alloc_result_buf(this_instance, &test_spec, &result_limit);
+ req->service_status = run_qualifying_tests(this_instance, false, &test_spec,
+ &summary, result_buf, result_limit);
- test_status = run_qualifying_tests(this_instance, false, &test_spec, &summary, result_buf, result_limit);
+ if (req->service_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
- call_req_set_opstatus(req, test_status);
+ rpc_status = serializer->serialize_run_tests_resp(resp_buf, &summary,
+ result_buf);
- if (test_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
+ free(result_buf);
+ }
+ }
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_run_tests_resp(resp_buf, &summary, result_buf);
-
- free(result_buf);
- }
- }
-
- return rpc_status;
+ return rpc_status;
}
-static rpc_status_t list_tests_handler(void *context, struct call_req* req)
+static rpc_status_t list_tests_handler(void *context, struct rpc_request *req)
{
- struct test_runner_provider *this_instance = (struct test_runner_provider*)context;
- rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
- struct test_spec test_spec;
-
- struct call_param_buf *req_buf = call_req_get_req_buf(req);
- const struct test_runner_provider_serializer *serializer = get_test_runner_serializer(this_instance, req);
+ struct test_runner_provider *this_instance = (struct test_runner_provider *)context;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct test_spec test_spec;
- if (serializer)
- rpc_status = serializer->deserialize_list_tests_req(req_buf, &test_spec);
+ struct rpc_buffer *req_buf = &req->request;
+ const struct test_runner_provider_serializer *serializer =
+ get_test_runner_serializer(this_instance, req);
- if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ if (serializer)
+ rpc_status = serializer->deserialize_list_tests_req(req_buf, &test_spec);
- int test_status;
- struct test_summary summary;
- size_t result_limit = 0;
- struct test_result *result_buf = alloc_result_buf(this_instance, &test_spec, &result_limit);
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+ struct test_summary summary;
+ size_t result_limit = 0;
+ struct test_result *result_buf =
+ alloc_result_buf(this_instance, &test_spec, &result_limit);
- test_status = run_qualifying_tests(this_instance, true, &test_spec, &summary, result_buf, result_limit);
+ req->service_status = run_qualifying_tests(this_instance, true, &test_spec,
+ &summary, result_buf, result_limit);
- call_req_set_opstatus(req, test_status);
+ if (req->service_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
+ struct rpc_buffer *resp_buf = &req->response;
- if (test_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
+ rpc_status = serializer->serialize_list_tests_resp(resp_buf, &summary,
+ result_buf);
- struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
- rpc_status = serializer->serialize_list_tests_resp(resp_buf, &summary, result_buf);
+ free(result_buf);
+ }
+ }
- free(result_buf);
- }
- }
-
- return rpc_status;
-} \ No newline at end of file
+ return rpc_status;
+}
diff --git a/components/service/test_runner/provider/test_runner_provider.h b/components/service/test_runner/provider/test_runner_provider.h
index e5c92304b..e81932d83 100644
--- a/components/service/test_runner/provider/test_runner_provider.h
+++ b/components/service/test_runner/provider/test_runner_provider.h
@@ -7,8 +7,7 @@
#ifndef TEST_RUNNER_PROVIDER_H
#define TEST_RUNNER_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
-#include <rpc_caller.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include <service/common/provider/service_provider.h>
#include <service/test_runner/provider/serializer/test_runner_provider_serializer.h>
#include <protocols/rpc/common/packed-c/encoding.h>
@@ -26,7 +25,7 @@ struct test_runner_provider
struct test_runner_backend *backend_list;
};
-struct rpc_interface *test_runner_provider_init(struct test_runner_provider *context);
+struct rpc_service_interface *test_runner_provider_init(struct test_runner_provider *context);
void test_runner_provider_deinit(struct test_runner_provider *context);
diff --git a/components/service/test_runner/provider/test_runner_uuid.h b/components/service/test_runner/provider/test_runner_uuid.h
new file mode 100644
index 000000000..c71b0588e
--- /dev/null
+++ b/components/service/test_runner/provider/test_runner_uuid.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEST_RUNNER_UUID_H
+#define TEST_RUNNER_UUID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TS_TEST_RUNNER_SERVICE_UUID \
+{ 0x33, 0xc7, 0x5b, 0xaf, 0xac, 0x6a, 0x4f, 0xe4, 0x8a, 0xc7, 0xe9, 0x90, 0x9b, 0xee, 0x2d, 0x17 }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_RUNNER_UUID_H */
diff --git a/components/service/test_runner/test/service/test_runner_service_tests.cpp b/components/service/test_runner/test/service/test_runner_service_tests.cpp
index 8d68bca05..850d46b11 100644
--- a/components/service/test_runner/test/service/test_runner_service_tests.cpp
+++ b/components/service/test_runner/test/service/test_runner_service_tests.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,22 +22,19 @@ TEST_GROUP(TestRunnerServiceTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_test_runner_service_context = NULL;
m_test_runner_client = NULL;
service_locator_init();
- m_test_runner_service_context = service_locator_query("sn:trustedfirmware.org:test-runner:0", &status);
+ m_test_runner_service_context = service_locator_query("sn:trustedfirmware.org:test-runner:0");
CHECK(m_test_runner_service_context);
- m_rpc_session_handle = service_context_open(m_test_runner_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_test_runner_service_context);
+ CHECK(m_rpc_session);
- m_test_runner_client = new test_runner_client(caller);
+ m_test_runner_client = new test_runner_client(m_rpc_session);
}
void teardown()
@@ -45,14 +42,18 @@ TEST_GROUP(TestRunnerServiceTests)
delete m_test_runner_client;
m_test_runner_client = NULL;
- service_context_close(m_test_runner_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_test_runner_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_test_runner_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_test_runner_service_context);
- m_test_runner_service_context = NULL;
+ service_context_relinquish(m_test_runner_service_context);
+ m_test_runner_service_context = NULL;
+ }
}
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_test_runner_service_context;
test_runner_client *m_test_runner_client;
};
diff --git a/components/service/smm_variable/backend/component.cmake b/components/service/uefi/smm_variable/backend/component.cmake
index 8a857b916..d7eea9e5b 100644
--- a/components/service/smm_variable/backend/component.cmake
+++ b/components/service/uefi/smm_variable/backend/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -14,3 +14,8 @@ target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/variable_index_iterator.c"
"${CMAKE_CURRENT_LIST_DIR}/variable_checker.c"
)
+
+set(UEFI_MAX_VARIABLE_SIZE "4096" CACHE STRING "Maximum size of UEFI variables")
+target_compile_definitions(${TGT} PRIVATE
+ DEFAULT_MAX_VARIABLE_SIZE=${UEFI_MAX_VARIABLE_SIZE}
+ )
diff --git a/components/service/uefi/smm_variable/backend/direct/component.cmake b/components/service/uefi/smm_variable/backend/direct/component.cmake
new file mode 100644
index 000000000..84d974cae
--- /dev/null
+++ b/components/service/uefi/smm_variable/backend/direct/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/uefi_direct_backend.c"
+ )
diff --git a/components/service/uefi/smm_variable/backend/direct/uefi_direct_backend.c b/components/service/uefi/smm_variable/backend/direct/uefi_direct_backend.c
new file mode 100644
index 000000000..bf978c5dd
--- /dev/null
+++ b/components/service/uefi/smm_variable/backend/direct/uefi_direct_backend.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <mbedtls/build_info.h>
+#include <mbedtls/pkcs7.h>
+#include <mbedtls/x509_crt.h>
+#include <stdint.h>
+
+int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cert_len,
+ const uint8_t *hash, uint64_t hash_len, const uint8_t *public_key_cert,
+ uint64_t public_key_cert_len)
+{
+ int mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+
+ /* Parse the public key certificate */
+ mbedtls_x509_crt signer_certificate;
+
+ mbedtls_x509_crt_init(&signer_certificate);
+
+ mbedtls_status = mbedtls_x509_crt_parse_der(&signer_certificate, public_key_cert,
+ public_key_cert_len);
+
+ if (mbedtls_status == 0) {
+ /* Parse the PKCS#7 DER encoded signature block */
+ mbedtls_pkcs7 pkcs7_structure;
+
+ mbedtls_pkcs7_init(&pkcs7_structure);
+
+ mbedtls_status = mbedtls_pkcs7_parse_der(&pkcs7_structure, signature_cert,
+ signature_cert_len);
+
+ if (mbedtls_status == MBEDTLS_PKCS7_SIGNED_DATA) {
+ /* Verify hash against signed hash */
+ mbedtls_status = mbedtls_pkcs7_signed_hash_verify(
+ &pkcs7_structure, &signer_certificate, hash, hash_len);
+ }
+
+ mbedtls_pkcs7_free(&pkcs7_structure);
+ }
+
+ mbedtls_x509_crt_free(&signer_certificate);
+
+ return mbedtls_status;
+}
diff --git a/components/service/smm_variable/backend/test/component.cmake b/components/service/uefi/smm_variable/backend/test/component.cmake
index 8464e6e2d..8464e6e2d 100644
--- a/components/service/smm_variable/backend/test/component.cmake
+++ b/components/service/uefi/smm_variable/backend/test/component.cmake
diff --git a/components/service/smm_variable/backend/test/variable_index_tests.cpp b/components/service/uefi/smm_variable/backend/test/variable_index_tests.cpp
index c8bacf973..1b7a6b879 100644
--- a/components/service/smm_variable/backend/test/variable_index_tests.cpp
+++ b/components/service/uefi/smm_variable/backend/test/variable_index_tests.cpp
@@ -1,16 +1,14 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <wchar.h>
+#include <CppUTest/TestHarness.h>
+#include <service/uefi/smm_variable/backend/variable_index.h>
+#include <service/uefi/smm_variable/backend/variable_index_iterator.h>
#include <string>
#include <vector>
-#include <CppUTest/TestHarness.h>
-#include <service/smm_variable/backend/variable_index.h>
-#include <service/smm_variable/backend/variable_index_iterator.h>
-
TEST_GROUP(UefiVariableIndexTests)
{
@@ -43,9 +41,10 @@ TEST_GROUP(UefiVariableIndexTests)
guid_2.Data4[6] = 0x16;
guid_2.Data4[7] = 0x17;
- name_1 = to_variable_name(L"var1");
- name_2 = to_variable_name(L"var2_nv");
- name_3 = to_variable_name(L"var3_nv");
+ name_1 = to_variable_name(u"var1");
+ name_2 = to_variable_name(u"var2_nv");
+ name_3 = to_variable_name(u"var3_nv");
+ null_name = to_variable_name(u"");
}
void teardown()
@@ -53,50 +52,40 @@ TEST_GROUP(UefiVariableIndexTests)
variable_index_deinit(&m_variable_index);
}
- std::vector<int16_t> to_variable_name(const std::wstring &string)
+ std::u16string to_variable_name(const char16_t *string)
{
- std::vector<int16_t> var_name;
-
- for (size_t i = 0; i < string.size(); i++) {
-
- var_name.push_back((int16_t)string[i]);
- }
-
+ std::u16string var_name(string);
var_name.push_back(0);
return var_name;
}
- void create_variables()
+ size_t string_get_size_in_bytes(const std::u16string &string)
{
- const struct variable_info *info = NULL;
+ return string.size() * sizeof(typename std::u16string::value_type);
+ }
- info = variable_index_add_variable(
- &m_variable_index,
- &guid_1,
- name_1.size() * sizeof(int16_t),
- name_1.data(),
- EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ void create_variables()
+ {
+ struct variable_info *info = NULL;
+ info = variable_index_add_entry(&m_variable_index, &guid_1,
+ string_get_size_in_bytes(name_1), (int16_t *) name_1.data());
CHECK_TRUE(info);
+ variable_index_set_variable(info, EFI_VARIABLE_BOOTSERVICE_ACCESS);
- info = variable_index_add_variable(
- &m_variable_index,
- &guid_2,
- name_2.size() * sizeof(int16_t),
- name_2.data(),
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS);
-
+ info = variable_index_add_entry(&m_variable_index, &guid_2,
+ string_get_size_in_bytes(name_2), (int16_t *) name_2.data());
CHECK_TRUE(info);
+ variable_index_set_variable(info, EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
- info = variable_index_add_variable(
- &m_variable_index,
- &guid_1,
- name_3.size() * sizeof(int16_t),
- name_3.data(),
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS);
-
+ info = variable_index_add_entry(&m_variable_index, &guid_1,
+ string_get_size_in_bytes(name_3), (int16_t *) name_3.data());
CHECK_TRUE(info);
+ variable_index_set_variable(info, EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
}
static const size_t MAX_VARIABLES = 10;
@@ -104,62 +93,50 @@ TEST_GROUP(UefiVariableIndexTests)
struct variable_index m_variable_index;
EFI_GUID guid_1;
EFI_GUID guid_2;
- std::vector<int16_t> name_1;
- std::vector<int16_t> name_2;
- std::vector<int16_t> name_3;
+ std::u16string name_1;
+ std::u16string name_2;
+ std::u16string name_3;
+ std::u16string null_name;
};
TEST(UefiVariableIndexTests, emptyIndexOperations)
{
- const struct variable_info *info = NULL;
+ efi_status_t status = EFI_SUCCESS;
+ struct variable_info *info = NULL;
/* Expect not to find a variable */
- info = variable_index_find(
- &m_variable_index,
- &guid_1,
- name_1.size() * sizeof(int16_t),
- name_1.data());
+ info = variable_index_find(&m_variable_index, &guid_1, string_get_size_in_bytes(name_1),
+ (const int16_t *) name_1.data());
POINTERS_EQUAL(NULL, info);
- /* Expect also not to find the next variable */
- info = variable_index_find_next(
- &m_variable_index,
- &guid_1,
- name_1.size() * sizeof(int16_t),
- name_1.data());
+ /* Expect also find next to be rejected */
+ info = variable_index_find_next(&m_variable_index, &guid_1, string_get_size_in_bytes(name_1),
+ (const int16_t *) name_1.data(), &status);
POINTERS_EQUAL(NULL, info);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, status);
/* Remove should silently return */
- variable_index_remove_variable(
- &m_variable_index,
- info);
+ variable_index_clear_variable(&m_variable_index, info);
}
TEST(UefiVariableIndexTests, addWithOversizedName)
{
- const struct variable_info *info = NULL;
- std::vector<int16_t> name;
+ struct variable_info *info = NULL;
+ std::u16string name;
- name = to_variable_name(L"a long variable name that exceeds the length limit");
+ name = to_variable_name(
+ u"a long variable name that exceeds the length limit with a few chars");
- info = variable_index_add_variable(
- &m_variable_index,
- &guid_1,
- name.size() * sizeof(int16_t),
- name.data(),
- EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ info = variable_index_add_entry(&m_variable_index, &guid_1, string_get_size_in_bytes(name),
+ (int16_t *) name.data());
/* Expect the add to fail because of an oversized name */
POINTERS_EQUAL(NULL, info);
- name = to_variable_name(L"a long variable name that fits!");
+ name = to_variable_name(u"a long variable name that fits!");
- info = variable_index_add_variable(
- &m_variable_index,
- &guid_1,
- name.size() * sizeof(int16_t),
- name.data(),
- EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ info = variable_index_add_entry(&m_variable_index, &guid_1, string_get_size_in_bytes(name),
+ (int16_t *) name.data());
/* Expect the add succeed */
CHECK_TRUE(info);
@@ -167,18 +144,13 @@ TEST(UefiVariableIndexTests, addWithOversizedName)
TEST(UefiVariableIndexTests, variableIndexFull)
{
- const struct variable_info *info = NULL;
+ struct variable_info *info = NULL;
EFI_GUID guid = guid_1;
/* Expect to be able to fill the index */
for (size_t i = 0; i < MAX_VARIABLES; ++i) {
-
- info = variable_index_add_variable(
- &m_variable_index,
- &guid,
- name_1.size() * sizeof(int16_t),
- name_1.data(),
- EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ info = variable_index_add_entry(&m_variable_index, &guid,
+ string_get_size_in_bytes(name_1), (int16_t *) name_1.data());
CHECK_TRUE(info);
@@ -187,60 +159,51 @@ TEST(UefiVariableIndexTests, variableIndexFull)
}
/* Variable index should now be full */
- info = variable_index_add_variable(
- &m_variable_index,
- &guid,
- name_1.size() * sizeof(int16_t),
- name_1.data(),
- EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ info = variable_index_add_entry(&m_variable_index, &guid, string_get_size_in_bytes(name_1),
+ (int16_t *) name_1.data());
POINTERS_EQUAL(NULL, info);
}
-
TEST(UefiVariableIndexTests, enumerateStore)
{
const struct variable_info *info = NULL;
- const std::vector<int16_t> null_name = to_variable_name(L"");
+ efi_status_t status = EFI_NOT_FOUND;
create_variables();
- info = variable_index_find_next(
- &m_variable_index,
- &guid_1,
- null_name.size() * sizeof(int16_t),
- null_name.data());
+ info = variable_index_find_next(&m_variable_index, &guid_1,
+ string_get_size_in_bytes(null_name), (const int16_t *) null_name.data(),
+ &status);
CHECK_TRUE(info);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
LONGS_EQUAL(EFI_VARIABLE_BOOTSERVICE_ACCESS, info->metadata.attributes);
MEMCMP_EQUAL(&guid_1, &info->metadata.guid, sizeof(EFI_GUID));
MEMCMP_EQUAL(name_1.data(), info->metadata.name, name_1.size());
- info = variable_index_find_next(
- &m_variable_index,
- &info->metadata.guid,
- info->metadata.name_size,
- info->metadata.name);
+ info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
+ info->metadata.name_size, info->metadata.name, &status);
CHECK_TRUE(info);
- LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, info->metadata.attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ info->metadata.attributes);
MEMCMP_EQUAL(&guid_2, &info->metadata.guid, sizeof(EFI_GUID));
MEMCMP_EQUAL(name_2.data(), info->metadata.name, name_2.size());
- info = variable_index_find_next(
- &m_variable_index,
- &info->metadata.guid,
- info->metadata.name_size,
- info->metadata.name);
+ info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
+ info->metadata.name_size, info->metadata.name, &status);
CHECK_TRUE(info);
- LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS, info->metadata.attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ info->metadata.attributes);
MEMCMP_EQUAL(&guid_1, &info->metadata.guid, sizeof(EFI_GUID));
MEMCMP_EQUAL(name_3.data(), info->metadata.name, name_3.size());
- info = variable_index_find_next(
- &m_variable_index,
- &info->metadata.guid,
- info->metadata.name_size,
- info->metadata.name);
+ info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
+ info->metadata.name_size, info->metadata.name, &status);
POINTERS_EQUAL(NULL, info);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
}
TEST(UefiVariableIndexTests, dumpLoadRoadtrip)
@@ -273,33 +236,29 @@ TEST(UefiVariableIndexTests, dumpLoadRoadtrip)
UNSIGNED_LONGS_EQUAL(dump_len, load_len);
/* Enumerate and now expect only NV variables to be present */
+ status = EFI_NOT_FOUND;
const struct variable_info *info = NULL;
- std::vector<int16_t> null_name = to_variable_name(L"");
- info = variable_index_find_next(
- &m_variable_index,
- &guid_1,
- null_name.size() * sizeof(int16_t),
- null_name.data());
+ info = variable_index_find_next(&m_variable_index, &guid_1,
+ string_get_size_in_bytes(null_name), (const int16_t *) null_name.data(),
+ &status);
CHECK_TRUE(info);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
- info->metadata.attributes);
+ info->metadata.attributes);
- info = variable_index_find_next(
- &m_variable_index,
- &info->metadata.guid,
- info->metadata.name_size,
- info->metadata.name);
+ info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
+ info->metadata.name_size, info->metadata.name, &status);
CHECK_TRUE(info);
- UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS,
- info->metadata.attributes);
-
- info = variable_index_find_next(
- &m_variable_index,
- &info->metadata.guid,
- info->metadata.name_size,
- info->metadata.name);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ info->metadata.attributes);
+
+ info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
+ info->metadata.name_size, info->metadata.name, &status);
POINTERS_EQUAL(NULL, info);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
}
TEST(UefiVariableIndexTests, dumpBufferTooSmall)
@@ -319,24 +278,18 @@ TEST(UefiVariableIndexTests, dumpBufferTooSmall)
UNSIGNED_LONGS_EQUAL(sizeof(struct variable_metadata) * 1, dump_len);
}
-
TEST(UefiVariableIndexTests, removeVariable)
{
uint8_t buffer[MAX_VARIABLES * sizeof(struct variable_metadata)];
- const struct variable_info *info = NULL;
+ struct variable_info *info = NULL;
create_variables();
/* Remove one of the NV variables */
- info = variable_index_find(
- &m_variable_index,
- &guid_2,
- name_2.size() * sizeof(int16_t),
- name_2.data());
+ info = variable_index_find(&m_variable_index, &guid_2, string_get_size_in_bytes(name_2),
+ (const int16_t *) name_2.data());
- variable_index_remove_variable(
- &m_variable_index,
- info);
+ variable_index_clear_variable(&m_variable_index, info);
/* Expect index to be dirty and for only one NV variable to be left */
size_t dump_len = 0;
@@ -346,15 +299,10 @@ TEST(UefiVariableIndexTests, removeVariable)
UNSIGNED_LONGS_EQUAL((sizeof(struct variable_metadata) * 1), dump_len);
/* Remove the volatile variable */
- info = variable_index_find(
- &m_variable_index,
- &guid_1,
- name_1.size() * sizeof(int16_t),
- name_1.data());
+ info = variable_index_find(&m_variable_index, &guid_1, string_get_size_in_bytes(name_1),
+ (const int16_t *) name_1.data());
- variable_index_remove_variable(
- &m_variable_index,
- info);
+ variable_index_clear_variable(&m_variable_index, info);
/* Expect index not to be dirty because there was no change to any NV variable */
dump_len = 0;
@@ -364,15 +312,10 @@ TEST(UefiVariableIndexTests, removeVariable)
UNSIGNED_LONGS_EQUAL((sizeof(struct variable_metadata) * 1), dump_len);
/* Remove the remaining NV variable */
- info = variable_index_find(
- &m_variable_index,
- &guid_1,
- name_3.size() * sizeof(int16_t),
- name_3.data());
+ info = variable_index_find(&m_variable_index, &guid_1, string_get_size_in_bytes(name_3),
+ (const int16_t *) name_3.data());
- variable_index_remove_variable(
- &m_variable_index,
- info);
+ variable_index_clear_variable(&m_variable_index, info);
/* Expect index to be dirty and dump to now be empty */
dump_len = 0;
@@ -383,19 +326,18 @@ TEST(UefiVariableIndexTests, removeVariable)
/* Enumerate and now expect an empty index */
info = NULL;
- std::vector<int16_t> null_name = to_variable_name(L"");
+ efi_status_t status = EFI_SUCCESS;
- info = variable_index_find_next(
- &m_variable_index,
- &guid_1,
- null_name.size() * sizeof(int16_t),
- null_name.data());
+ info = variable_index_find_next(&m_variable_index, &guid_1,
+ string_get_size_in_bytes(null_name), (const int16_t *) null_name.data(),
+ &status);
POINTERS_EQUAL(NULL, info);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
}
TEST(UefiVariableIndexTests, checkIterator)
{
- const struct variable_info *info = NULL;
+ struct variable_info *info = NULL;
create_variables();
@@ -407,7 +349,7 @@ TEST(UefiVariableIndexTests, checkIterator)
/* Check first entry is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_1.size() * sizeof(int16_t), info->metadata.name_size);
+ UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_1), info->metadata.name_size);
MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
variable_index_iterator_next(&iter);
@@ -416,10 +358,10 @@ TEST(UefiVariableIndexTests, checkIterator)
/* Check next is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_2.size() * sizeof(int16_t), info->metadata.name_size);
+ UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_2), info->metadata.name_size);
MEMCMP_EQUAL(name_2.data(), info->metadata.name, info->metadata.name_size);
- const struct variable_info *info_to_remove = info;
+ struct variable_info *info_to_remove = info;
variable_index_iterator_next(&iter);
CHECK_FALSE(variable_index_iterator_is_done(&iter));
@@ -427,7 +369,7 @@ TEST(UefiVariableIndexTests, checkIterator)
/* Check next is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_3.size() * sizeof(int16_t), info->metadata.name_size);
+ UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_3), info->metadata.name_size);
MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
/* Expect iterating to be done */
@@ -435,7 +377,8 @@ TEST(UefiVariableIndexTests, checkIterator)
CHECK_TRUE(variable_index_iterator_is_done(&iter));
/* Now remove the middle entry */
- variable_index_remove_variable(&m_variable_index, info_to_remove);
+ variable_index_clear_variable(&m_variable_index, info_to_remove);
+ variable_index_remove_unused_entry(&m_variable_index, info_to_remove);
/* Iterate again but this time there should only be two entries */
variable_index_iterator_first(&iter, &m_variable_index);
@@ -444,7 +387,7 @@ TEST(UefiVariableIndexTests, checkIterator)
/* Check first entry is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_1.size() * sizeof(int16_t), info->metadata.name_size);
+ UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_1), info->metadata.name_size);
MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
variable_index_iterator_next(&iter);
@@ -453,7 +396,7 @@ TEST(UefiVariableIndexTests, checkIterator)
/* Check next entry is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_3.size() * sizeof(int16_t), info->metadata.name_size);
+ UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_3), info->metadata.name_size);
MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
/* Expect iterating to be done */
@@ -478,17 +421,14 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
constraints.max_size = 100;
/* Set check constraints on one of the variables */
- const struct variable_info *info = variable_index_find(
- &m_variable_index,
- &guid_2,
- name_2.size() * sizeof(int16_t),
- name_2.data());
+ struct variable_info *info = variable_index_find(
+ &m_variable_index, &guid_2, string_get_size_in_bytes(name_2), (const int16_t *) name_2.data());
CHECK_TRUE(info);
CHECK_TRUE(info->is_variable_set);
CHECK_FALSE(info->is_constraints_set);
- variable_index_update_constraints(info, &constraints);
+ variable_index_set_constraints(info, &constraints);
CHECK_TRUE(info->is_constraints_set);
CHECK_TRUE(info->is_variable_set);
@@ -496,15 +436,10 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
/* Remove the variable but still expect the variable to be indexed
* because of the set constraints.
*/
- variable_index_remove_variable(
- &m_variable_index,
- info);
+ variable_index_clear_variable(&m_variable_index, info);
- info = variable_index_find(
- &m_variable_index,
- &guid_2,
- name_2.size() * sizeof(int16_t),
- name_2.data());
+ info = variable_index_find(&m_variable_index, &guid_2, string_get_size_in_bytes(name_2),
+ (const int16_t *) name_2.data());
CHECK_TRUE(info);
CHECK_FALSE(info->is_variable_set);
@@ -512,31 +447,27 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
/* Enumerate over variables, only expecting to find the two remaining 'set' variables. */
info = NULL;
- std::vector<int16_t> null_name = to_variable_name(L"");
+ efi_status_t status = EFI_NOT_FOUND;
- info = variable_index_find_next(
- &m_variable_index,
- &guid_1,
- null_name.size() * sizeof(int16_t),
- null_name.data());
+ info = variable_index_find_next(&m_variable_index, &guid_1,
+ string_get_size_in_bytes(null_name), (const int16_t *) null_name.data(),
+ &status);
CHECK_TRUE(info);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_BOOTSERVICE_ACCESS, info->metadata.attributes);
- info = variable_index_find_next(
- &m_variable_index,
- &info->metadata.guid,
- info->metadata.name_size,
- info->metadata.name);
+ info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
+ info->metadata.name_size, info->metadata.name, &status);
CHECK_TRUE(info);
- UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS,
- info->metadata.attributes);
-
- info = variable_index_find_next(
- &m_variable_index,
- &info->metadata.guid,
- info->metadata.name_size,
- info->metadata.name);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ info->metadata.attributes);
+
+ info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
+ info->metadata.name_size, info->metadata.name, &status);
CHECK_FALSE(info);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
/* Iterating over the index should still return all three because the set constraints
* for variable 2 still persist.
@@ -549,7 +480,7 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
/* Check first entry is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_1.size() * sizeof(int16_t), info->metadata.name_size);
+ UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_1), info->metadata.name_size);
MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
variable_index_iterator_next(&iter);
@@ -558,7 +489,7 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
/* Check next is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_2.size() * sizeof(int16_t), info->metadata.name_size);
+ UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_2), info->metadata.name_size);
MEMCMP_EQUAL(name_2.data(), info->metadata.name, info->metadata.name_size);
variable_index_iterator_next(&iter);
@@ -567,7 +498,7 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
/* Check next is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_3.size() * sizeof(int16_t), info->metadata.name_size);
+ UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_3), info->metadata.name_size);
MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
/* Expect iterating to be done */
@@ -588,28 +519,25 @@ TEST(UefiVariableIndexTests, setCheckConstraintsNonExistingVar)
constraints.max_size = 100;
/* Initially expect no variable_info */
- const struct variable_info *info = variable_index_find(
- &m_variable_index,
- &guid_2,
- name_2.size() * sizeof(int16_t),
- name_2.data());
+ struct variable_info *info = variable_index_find(
+ &m_variable_index, &guid_2, string_get_size_in_bytes(name_2),
+ (const int16_t *) name_2.data());
CHECK_FALSE(info);
/* Adding the check constraints should result in an entry being added */
- info = variable_index_add_constraints(
- &m_variable_index,
- &guid_2,
- name_2.size() * sizeof(int16_t),
- name_2.data(),
- &constraints);
-
+ info = variable_index_add_entry(
+ &m_variable_index, &guid_2, string_get_size_in_bytes(name_2),
+ (const int16_t *) name_2.data());
CHECK_TRUE(info);
+
+ variable_index_set_constraints(info, &constraints);
CHECK_FALSE(info->is_variable_set);
CHECK_TRUE(info->is_constraints_set);
/* Updating the variable should cause the variable to be marked as set */
- variable_index_update_variable(info, EFI_VARIABLE_RUNTIME_ACCESS);
+ variable_index_set_variable(info,
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS);
CHECK_TRUE(info->is_variable_set);
CHECK_TRUE(info->is_constraints_set);
diff --git a/components/service/uefi/smm_variable/backend/test/variable_store_tests.cpp b/components/service/uefi/smm_variable/backend/test/variable_store_tests.cpp
new file mode 100644
index 000000000..0d3450e77
--- /dev/null
+++ b/components/service/uefi/smm_variable/backend/test/variable_store_tests.cpp
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <service/secure_storage/backend/mock_store/mock_store.h>
+#include <service/uefi/smm_variable/backend/uefi_variable_store.h>
+#include <string.h>
+#include <string>
+#include <vector>
+
+TEST_GROUP(UefiVariableStoreTests)
+{
+ void setup()
+ {
+ m_persistent_backend = mock_store_init(&m_persistent_store);
+ m_volatile_backend = mock_store_init(&m_volatile_store);
+
+ efi_status_t status = uefi_variable_store_init(&m_uefi_variable_store, OWNER_ID,
+ MAX_VARIABLES, m_persistent_backend,
+ m_volatile_backend);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ uefi_variable_store_set_storage_limits(&m_uefi_variable_store,
+ EFI_VARIABLE_NON_VOLATILE, STORE_CAPACITY,
+ MAX_VARIABLE_SIZE);
+
+ uefi_variable_store_set_storage_limits(&m_uefi_variable_store, 0, STORE_CAPACITY,
+ MAX_VARIABLE_SIZE);
+ }
+
+ void teardown()
+ {
+ uefi_variable_store_deinit(&m_uefi_variable_store);
+ mock_store_reset(&m_persistent_store);
+ mock_store_reset(&m_volatile_store);
+ }
+
+ std::u16string to_variable_name(const std::u16string &string)
+ {
+ std::u16string var_name(string);
+
+ /* Add mandatory null terminator */
+ var_name.push_back(0);
+
+ return var_name;
+ }
+
+ std::u16string to_variable_name(const char16_t *string)
+ {
+ std::u16string var_name(string);
+ var_name.push_back(0);
+ return var_name;
+ }
+
+ size_t string_get_size_in_bytes(const std::u16string &string)
+ {
+ return string.size() * sizeof(uint16_t);
+ }
+
+ bool compare_variable_name(const std::u16string &expected, const int16_t *name,
+ size_t name_size)
+ {
+ std::u16string var_name = to_variable_name(expected);
+
+ if (name_size != string_get_size_in_bytes(var_name))
+ return false;
+
+ return 0==memcmp(name, var_name.data(), name_size);
+ }
+
+ efi_status_t set_variable(const std::u16string &name, const uint8_t *data, size_t data_size,
+ uint32_t attributes, EFI_GUID *guid = NULL)
+ {
+ std::u16string var_name = to_variable_name(name);
+ size_t name_size = string_get_size_in_bytes(var_name);
+
+ /* Use a vector as a temporary buffer to move allocation to the HEAP and for RAII benefits. */
+ std::vector<uint8_t> msg_buffer(
+ (std::size_t)SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, data_size));
+
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_variable =
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) msg_buffer.data();
+
+ if (!guid)
+ guid = &m_common_guid;
+ access_variable->Guid = *guid;
+ access_variable->Attributes = attributes;
+
+ access_variable->NameSize = name_size;
+ memcpy(access_variable->Name, var_name.data(), name_size);
+
+ access_variable->DataSize = data_size;
+ memcpy(msg_buffer.data() +
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_variable),
+ data, data_size);
+
+ efi_status_t status =
+ uefi_variable_store_set_variable(&m_uefi_variable_store, access_variable);
+
+ return status;
+ }
+
+ efi_status_t set_variable(const std::u16string &name, const std::string &data,
+ uint32_t attributes, EFI_GUID *guid = NULL)
+ {
+ return set_variable(name, (uint8_t *) data.data(), data.size(),
+ attributes, guid);
+ }
+
+ efi_status_t get_variable(const std::u16string &name, std::string &data,
+ size_t data_len_clamp = VARIABLE_BUFFER_SIZE)
+ {
+ std::u16string var_name = to_variable_name(name);
+ size_t name_size = string_get_size_in_bytes(var_name);
+
+ size_t total_size = 0;
+ std::vector<uint8_t> msg_buffer(VARIABLE_BUFFER_SIZE);
+
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_variable =
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) msg_buffer.data();
+
+ access_variable->Guid = m_common_guid;
+ access_variable->Attributes = 0;
+
+ access_variable->NameSize = name_size;
+ memcpy(access_variable->Name, var_name.data(), name_size);
+
+ size_t max_data_len =
+ (data_len_clamp == VARIABLE_BUFFER_SIZE) ?
+ VARIABLE_BUFFER_SIZE -
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(
+ access_variable) :
+ data_len_clamp;
+
+ access_variable->DataSize = max_data_len;
+
+ efi_status_t status = uefi_variable_store_get_variable(
+ &m_uefi_variable_store, access_variable, max_data_len, &total_size);
+
+ data.clear();
+
+ if (status == EFI_SUCCESS) {
+ const char *data_start =
+ (const char *) (msg_buffer.data() +
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(
+ access_variable));
+
+ data = std::string(data_start, access_variable->DataSize);
+
+ UNSIGNED_LONGLONGS_EQUAL(
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_TOTAL_SIZE(
+ access_variable),
+ total_size);
+ } else if (status == EFI_BUFFER_TOO_SMALL) {
+ /* String length set to reported variable length */
+ data.insert(0, access_variable->DataSize, '!');
+
+ UNSIGNED_LONGLONGS_EQUAL(
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(
+ access_variable),
+ total_size);
+ }
+
+ return status;
+ }
+
+ efi_status_t query_variable_info(uint32_t attributes, size_t * max_variable_storage_size,
+ size_t * remaining_variable_storage_size,
+ size_t * max_variable_size)
+ {
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO query;
+
+ query.MaximumVariableStorageSize = 0;
+ query.RemainingVariableStorageSize = 0;
+ query.MaximumVariableSize = 0;
+ query.Attributes = attributes;
+
+ efi_status_t status =
+ uefi_variable_store_query_variable_info(&m_uefi_variable_store, &query);
+
+ if (status == EFI_SUCCESS) {
+ *max_variable_storage_size = query.MaximumVariableStorageSize;
+ *remaining_variable_storage_size = query.RemainingVariableStorageSize;
+ *max_variable_size = query.MaximumVariableSize;
+ }
+
+ return status;
+ }
+
+ efi_status_t set_check_var_property(const std::u16string &name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property)
+ {
+ std::u16string var_name = to_variable_name(name);
+ size_t name_size = string_get_size_in_bytes(var_name);
+
+ std::vector<uint8_t> msg_buffer(
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size));
+
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *check_var =
+ (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) msg_buffer.data();
+
+ check_var->Guid = m_common_guid;
+ check_var->NameSize = name_size;
+ memcpy(check_var->Name, var_name.data(), name_size);
+
+ check_var->VariableProperty = check_property;
+
+ efi_status_t status = uefi_variable_store_set_var_check_property(
+ &m_uefi_variable_store, check_var);
+
+ return status;
+ }
+
+ void zap_stored_variable(const std::u16string &name)
+ {
+ std::u16string var_name = to_variable_name(name);
+ size_t name_size = string_get_size_in_bytes(var_name);
+
+ /* Create the condition where a variable is indexed but
+ * there is no corresponding stored object.
+ */
+ struct variable_index *variable_index = &m_uefi_variable_store.variable_index;
+
+ const struct variable_info *info = variable_index_find(
+ variable_index, &m_common_guid, name_size,
+ (const int16_t *) var_name.data());
+
+ if (info && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
+ struct storage_backend *storage_backend =
+ m_uefi_variable_store.persistent_store.storage_backend;
+
+ storage_backend->interface->remove(storage_backend->context, OWNER_ID,
+ info->metadata.uid);
+ }
+ }
+
+ void power_cycle()
+ {
+ /* Simulate a power-cycle */
+ uefi_variable_store_deinit(&m_uefi_variable_store);
+
+ /* Lose volatile store contents */
+ mock_store_reset(&m_volatile_store);
+
+ efi_status_t status = uefi_variable_store_init(&m_uefi_variable_store, OWNER_ID,
+ MAX_VARIABLES, m_persistent_backend,
+ m_volatile_backend);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ uefi_variable_store_set_storage_limits(&m_uefi_variable_store,
+ EFI_VARIABLE_NON_VOLATILE, STORE_CAPACITY,
+ MAX_VARIABLE_SIZE);
+
+ uefi_variable_store_set_storage_limits(&m_uefi_variable_store, 0, STORE_CAPACITY,
+ MAX_VARIABLE_SIZE);
+ }
+
+ static const size_t MAX_VARIABLES = 10;
+ static const size_t MAX_VARIABLE_SIZE = 3000;
+ static const size_t STORE_CAPACITY = 10000;
+
+ static const uint32_t OWNER_ID = 100;
+ static const size_t VARIABLE_BUFFER_SIZE = 1024;
+
+ struct uefi_variable_store m_uefi_variable_store;
+ struct mock_store m_persistent_store;
+ struct mock_store m_volatile_store;
+ struct storage_backend *m_persistent_backend;
+ struct storage_backend *m_volatile_backend;
+
+ EFI_GUID m_common_guid = { 0x01234567,
+ 0x89ab,
+ 0xCDEF,
+ { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
+};
+
+TEST(UefiVariableStoreTests, setGetRoundtrip)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name = u"test_variable";
+ std::string input_data = "quick brown fox";
+ std::string output_data;
+
+ status = set_variable(var_name, input_data, EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect got variable data to be the same as the set value */
+ UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+
+ /* Extend the variable using an append write */
+ std::string input_data2 = " jumps over the lazy dog";
+
+ status = set_variable(var_name, input_data2,
+ EFI_VARIABLE_APPEND_WRITE | EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ std::string expected_output = input_data + input_data2;
+
+ /* Expect the append write operation to have extended the variable */
+ UNSIGNED_LONGLONGS_EQUAL(expected_output.size(), output_data.size());
+ LONGS_EQUAL(0, expected_output.compare(output_data));
+
+ /* Expect query_variable_info to return consistent values */
+ size_t max_variable_storage_size = 0;
+ size_t remaining_variable_storage_size = 0;
+ size_t max_variable_size = 0;
+
+ status = query_variable_info(0, &max_variable_storage_size,
+ &remaining_variable_storage_size, &max_variable_size);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY, max_variable_storage_size);
+ UNSIGNED_LONGLONGS_EQUAL(MAX_VARIABLE_SIZE, max_variable_size);
+ UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY - expected_output.size(),
+ remaining_variable_storage_size);
+}
+
+TEST(UefiVariableStoreTests, persistentSetGet)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name = u"test_variable";
+ std::string input_data = "quick brown fox";
+ std::string output_data;
+
+ status = set_variable(var_name, input_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect got variable data to be the same as the set value */
+ UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+
+ /* Extend the variable using an append write */
+ std::string input_data2 = " jumps over the lazy dog";
+
+ status = set_variable(var_name, input_data2,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_APPEND_WRITE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ std::string expected_output = input_data + input_data2;
+
+ /* Expect the append write operation to have extended the variable */
+ UNSIGNED_LONGLONGS_EQUAL(expected_output.size(), output_data.size());
+ LONGS_EQUAL(0, expected_output.compare(output_data));
+
+ /* Expect the variable to survive a power cycle */
+ power_cycle();
+
+ output_data = std::string();
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Still expect got variable data to be the same as the set value */
+ UNSIGNED_LONGLONGS_EQUAL(expected_output.size(), output_data.size());
+ LONGS_EQUAL(0, expected_output.compare(output_data));
+
+ /* Expect query_variable_info to return consistent values */
+ size_t max_variable_storage_size = 0;
+ size_t remaining_variable_storage_size = 0;
+ size_t max_variable_size = 0;
+
+ status = query_variable_info(EFI_VARIABLE_NON_VOLATILE, &max_variable_storage_size,
+ &remaining_variable_storage_size, &max_variable_size);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY, max_variable_storage_size);
+ UNSIGNED_LONGLONGS_EQUAL(MAX_VARIABLE_SIZE, max_variable_size);
+ UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY - expected_output.size(),
+ remaining_variable_storage_size);
+}
+
+TEST(UefiVariableStoreTests, getWithSmallBuffer)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name = u"test_variable";
+ std::string input_data = "quick brown fox";
+ std::string output_data;
+
+ /* A get with a zero length buffer is a legitimate way to
+ * discover the variable size. This test performs GetVariable
+ * operations with various buffer small buffer sizes. */
+ status = set_variable(var_name, input_data, 0);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* First get the variable without a constrained buffer */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect got variable data to be the same as the set value */
+ UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+
+ /* Now try with a zero length buffer */
+ status = get_variable(var_name, output_data, 0);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_BUFFER_TOO_SMALL, status);
+ UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
+
+ /* Try with a non-zero length but too small buffer */
+ status = get_variable(var_name, output_data, input_data.size() - 1);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_BUFFER_TOO_SMALL, status);
+ UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
+}
+
+TEST(UefiVariableStoreTests, removeVolatile)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name = u"rm_volatile_variable";
+ std::string input_data = "quick brown fox";
+ std::string output_data;
+
+ status = set_variable(var_name, input_data, 0);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Remove by setting with zero data length */
+ status = set_variable(var_name, std::string(), 0);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect variable to no loger exist */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+}
+
+TEST(UefiVariableStoreTests, removePersistent)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name = u"rm_nv_variable";
+ std::string input_data = "quick brown fox";
+ std::string output_data;
+
+ /* Attempt to remove a non-existed variable */
+ status = set_variable(var_name, std::string(), EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+
+ /* Create a variable */
+ status = set_variable(var_name, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Remove by setting with zero data length */
+ status = set_variable(var_name, std::string(), EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect variable to no loger exist */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+}
+
+TEST(UefiVariableStoreTests, bootServiceAccess)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name = u"test_variable";
+ std::string input_data = "a variable with access restricted to boot";
+ std::string output_data;
+
+ status = set_variable(var_name, input_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* 'Reboot' */
+ power_cycle();
+
+ /* Expect access to be permitted */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+
+ /* End of boot phase */
+ status = uefi_variable_store_exit_boot_service(&m_uefi_variable_store);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect access to be blocked for get_variable */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+
+ /* Expect access to be blocked for get_next_variable_name */
+ std::vector<uint8_t> msg_buffer(VARIABLE_BUFFER_SIZE);
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *next_name =
+ (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) msg_buffer.data();
+ size_t max_name_len =
+ VARIABLE_BUFFER_SIZE - SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
+
+ size_t total_len = 0;
+ next_name->NameSize = sizeof(int16_t);
+ next_name->Name[0] = 0;
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+}
+
+TEST(UefiVariableStoreTests, runtimeAccess)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name = u"test_variable";
+ std::string input_data = "a variable with access restricted to runtime";
+ std::string output_data;
+
+ /*
+ * Client is responsible for setting bootservice access whenever runtime
+ * access is specified. This checks the defense against invalid attributes.
+ */
+ status = set_variable(var_name, input_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, status);
+
+ status = set_variable(var_name, input_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* 'Reboot' */
+ power_cycle();
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* End of boot phase */
+ status = uefi_variable_store_exit_boot_service(&m_uefi_variable_store);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect access to be permitted */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+}
+
+TEST(UefiVariableStoreTests, enumerateStoreContents)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name_1 = u"test_variable_1";
+ std::u16string var_name_2 = u"test_variable_2";
+ std::u16string var_name_3 = u"test_variable_3";
+ std::string input_data = "blah blah";
+
+ /* Add some variables - a mixture of NV and volatile */
+ status = set_variable(var_name_1, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = set_variable(var_name_2, input_data, 0);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = set_variable(var_name_3, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Prepare to enumerate */
+ size_t total_len = 0;
+ std::vector<uint8_t> msg_buffer(VARIABLE_BUFFER_SIZE);
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *next_name =
+ (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) msg_buffer.data();
+ size_t max_name_len =
+ VARIABLE_BUFFER_SIZE - SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
+
+ /* First check handling of invalid variable name */
+ std::u16string bogus_name = to_variable_name(u"bogus_variable");
+ size_t bogus_name_size = string_get_size_in_bytes(bogus_name);
+ next_name->Guid = m_common_guid;
+ next_name->NameSize = bogus_name_size;
+ memcpy(next_name->Name, bogus_name.data(), bogus_name_size);
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, status);
+
+ /* Enumerate store contents */
+ next_name->NameSize = sizeof(int16_t);
+ next_name->Name[0] = 0;
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_1, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_2, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_3, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+
+ power_cycle();
+
+ /* Enumerate again - should be left with just NV variables.
+ * Use a different but equally valid null name.
+ */
+ next_name->NameSize = 10 * sizeof(int16_t);
+ memset(next_name->Name, 0, next_name->NameSize);
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_1, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_3, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+}
+
+TEST(UefiVariableStoreTests, failedNvSet)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name_1 = u"test_variable_1";
+ std::u16string var_name_2 = u"test_variable_2";
+ std::u16string var_name_3 = u"test_variable_3";
+ std::string input_data = "blah blah";
+
+ /* Add some variables - a mixture of NV and volatile */
+ status = set_variable(var_name_1, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = set_variable(var_name_2, input_data, 0);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = set_variable(var_name_3, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Simulate a power failure which resulted in the
+ * variable index being written but not the corresponding
+ * data.
+ */
+ zap_stored_variable(var_name_3);
+ power_cycle();
+
+ /* After the power cycle, we expect the volatile variable
+ * to have gone and for the index to have been cleaned up
+ * for the failed variable 3.
+ */
+ std::vector<uint8_t> msg_buffer(VARIABLE_BUFFER_SIZE);
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *next_name =
+ (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) msg_buffer.data();
+ size_t max_name_len =
+ VARIABLE_BUFFER_SIZE - SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
+
+ /* Enumerate store contents */
+ size_t total_len = 0;
+ next_name->NameSize = sizeof(int16_t);
+ next_name->Name[0] = 0;
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_1, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(&m_uefi_variable_store, next_name,
+ max_name_len, &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+}
+
+TEST(UefiVariableStoreTests, unsupportedAttribute)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name_1 = u"test_variable_1";
+ std::string input_data = "blah blah";
+
+ /* Add a variable with an unsupported attribute */
+ status = set_variable(var_name_1, input_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_UNSUPPORTED, status);
+}
+
+TEST(UefiVariableStoreTests, readOnlycheck)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name_1 = u"test_variable_1";
+ std::string input_data = "blah blah";
+
+ /* Add a variable */
+ status = set_variable(var_name_1, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Apply a check to constrain to Read Only */
+ VAR_CHECK_VARIABLE_PROPERTY check_property;
+ check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ check_property.Attributes = 0;
+ check_property.Property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ check_property.MinSize = 0;
+ check_property.MaxSize = 100;
+
+ status = set_check_var_property(var_name_1, check_property);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Subsequent set operations should fail */
+ status = set_variable(var_name_1, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_WRITE_PROTECTED, status);
+}
+
+TEST(UefiVariableStoreTests, noRemoveCheck)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::u16string var_name_1 = u"test_variable_1";
+ std::string input_data = "blah blah";
+
+ /* Add a variable */
+ status = set_variable(var_name_1, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Apply a check to constrain size to > 0. This should prevent removal */
+ VAR_CHECK_VARIABLE_PROPERTY check_property;
+ check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ check_property.Attributes = 0;
+ check_property.Property = 0;
+ check_property.MinSize = 1;
+ check_property.MaxSize = 10;
+
+ status = set_check_var_property(var_name_1, check_property);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Try and remove by setting with zero length data */
+ status = set_variable(var_name_1, std::string(), EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, status);
+
+ /* Setting with non zero data should work */
+ status = set_variable(var_name_1, std::string("Good"), EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* But with data that exceeds the MaxSize */
+ status = set_variable(var_name_1, std::string("A data value that exceeds the MaxSize"),
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, status);
+}
diff --git a/components/service/uefi/smm_variable/backend/uefi_variable_store.c b/components/service/uefi/smm_variable/backend/uefi_variable_store.c
new file mode 100644
index 000000000..8dad12d36
--- /dev/null
+++ b/components/service/uefi/smm_variable/backend/uefi_variable_store.c
@@ -0,0 +1,1590 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*
+ * This file implements the authenticated variable handling defined by UEFI standard.
+ * The UEFI comments refer to v2.9 of the specification:
+ * https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf
+ */
+#include "uefi_variable_store.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "trace.h"
+#include "util.h"
+#include "variable_checker.h"
+#include "variable_index_iterator.h"
+
+#if defined(UEFI_AUTH_VAR)
+#include "psa/crypto.h"
+#include "service/crypto/client/psa/crypto_client.h"
+#endif
+
+static void load_variable_index(struct uefi_variable_store *context);
+
+static efi_status_t sync_variable_index(const struct uefi_variable_store *context);
+
+static efi_status_t check_capabilities(const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
+
+static efi_status_t check_access_permitted(const struct uefi_variable_store *context,
+ const struct variable_info *info);
+
+static efi_status_t
+check_access_permitted_on_set(const struct uefi_variable_store *context,
+ const struct variable_info *info,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
+
+#if defined(UEFI_AUTH_VAR)
+static bool compare_guid(const EFI_GUID *guid1, const EFI_GUID *guid2);
+
+/* Creating a map of the EFI SMM variable for easier access */
+typedef struct {
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *smm_variable;
+ const uint8_t *smm_variable_data;
+ const EFI_VARIABLE_AUTHENTICATION_2 *efi_auth_descriptor;
+ size_t efi_auth_descriptor_len;
+ size_t efi_auth_descriptor_certdata_len;
+ const uint8_t *payload;
+ size_t payload_len;
+ const EFI_SIGNATURE_LIST *efi_signature_list;
+} efi_data_map;
+
+static bool init_efi_data_map(const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
+ bool with_auth_hdr, efi_data_map *map);
+
+static void create_smm_variable(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE **variable,
+ size_t name_size, size_t data_size, const uint8_t *name,
+ EFI_GUID *guid);
+
+static bool calc_variable_hash(const efi_data_map *var_map, uint8_t *hash_buffer,
+ size_t hash_buffer_size, size_t *hash_len);
+
+static efi_status_t
+select_verification_keys(const efi_data_map new_var, EFI_GUID global_variable_guid,
+ EFI_GUID security_database_guid, uint64_t maximum_variable_size,
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE **allowed_key_store_variables);
+
+static efi_status_t verify_var_by_key_var(const efi_data_map *new_var,
+ const efi_data_map *key_store_var,
+ const uint8_t *hash_buffer, size_t hash_len);
+
+static efi_status_t authenticate_variable(const struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
+#endif
+
+static efi_status_t store_variable_data(const struct uefi_variable_store *context,
+ const struct variable_info *info,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
+
+static efi_status_t remove_variable_data(const struct uefi_variable_store *context,
+ const struct variable_info *info);
+
+static efi_status_t load_variable_data(const struct uefi_variable_store *context,
+ const struct variable_info *info,
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
+ size_t max_data_len);
+
+static psa_status_t store_overwrite(struct delegate_variable_store *delegate_store,
+ uint32_t client_id, uint64_t uid, size_t data_length,
+ const void *data);
+
+static psa_status_t store_append_write(struct delegate_variable_store *delegate_store,
+ uint32_t client_id, uint64_t uid, size_t data_length,
+ const void *data);
+
+static void purge_orphan_index_entries(const struct uefi_variable_store *context);
+
+static struct delegate_variable_store *
+select_delegate_store(const struct uefi_variable_store *context, uint32_t attributes);
+
+static size_t space_used(const struct uefi_variable_store *context, uint32_t attributes,
+ struct storage_backend *storage_backend);
+
+static efi_status_t psa_to_efi_storage_status(psa_status_t psa_status);
+
+static efi_status_t check_name_terminator(const int16_t *name, size_t name_size);
+
+#if defined(UEFI_AUTH_VAR)
+static bool compare_name_to_key_store_name(const int16_t *name1, size_t size1,
+ const uint16_t *name2, size_t size2);
+#endif
+
+/* Private UID for storing the variable index - may be overridden at build-time */
+#ifndef SMM_VARIABLE_INDEX_STORAGE_UID
+#define SMM_VARIABLE_INDEX_STORAGE_UID (1)
+#endif
+
+/* Default maximum variable size -
+ * may be overridden using uefi_variable_store_set_storage_limits()
+ */
+#ifndef DEFAULT_MAX_VARIABLE_SIZE
+#define DEFAULT_MAX_VARIABLE_SIZE (4096)
+#endif
+
+efi_status_t uefi_variable_store_init(struct uefi_variable_store *context, uint32_t owner_id,
+ size_t max_variables,
+ struct storage_backend *persistent_store,
+ struct storage_backend *volatile_store)
+{
+ efi_status_t status = EFI_SUCCESS;
+
+ /* Initialise persistent store defaults */
+ context->persistent_store.is_nv = true;
+ context->persistent_store.max_variable_size = DEFAULT_MAX_VARIABLE_SIZE;
+ context->persistent_store.total_capacity = DEFAULT_MAX_VARIABLE_SIZE * max_variables;
+ context->persistent_store.storage_backend = persistent_store;
+
+ /* Initialise volatile store defaults */
+ context->volatile_store.is_nv = false;
+ context->volatile_store.max_variable_size = DEFAULT_MAX_VARIABLE_SIZE;
+ context->volatile_store.total_capacity = DEFAULT_MAX_VARIABLE_SIZE * max_variables;
+ context->volatile_store.storage_backend = volatile_store;
+
+ context->owner_id = owner_id;
+ context->is_boot_service = true;
+
+ status = variable_index_init(&context->variable_index, max_variables);
+
+ if (status == EFI_SUCCESS) {
+ /* Allocate a buffer for synchronizing the variable index with the persistent store */
+ context->index_sync_buffer_size =
+ variable_index_max_dump_size(&context->variable_index);
+ context->index_sync_buffer = NULL;
+
+ if (context->index_sync_buffer_size) {
+ context->index_sync_buffer = malloc(context->index_sync_buffer_size);
+ status = (context->index_sync_buffer) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Load the variable index with NV variable info from the persistent store */
+ if (context->index_sync_buffer) {
+ load_variable_index(context);
+ purge_orphan_index_entries(context);
+ }
+ }
+
+ return status;
+}
+
+void uefi_variable_store_deinit(struct uefi_variable_store *context)
+{
+ variable_index_deinit(&context->variable_index);
+
+ free(context->index_sync_buffer);
+ context->index_sync_buffer = NULL;
+}
+
+void uefi_variable_store_set_storage_limits(const struct uefi_variable_store *context,
+ uint32_t attributes, size_t total_capacity,
+ size_t max_variable_size)
+{
+ struct delegate_variable_store *delegate_store = select_delegate_store(context, attributes);
+
+ delegate_store->total_capacity = total_capacity;
+ delegate_store->max_variable_size = max_variable_size;
+}
+
+efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *context,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
+{
+ bool should_sync_index = false;
+
+ /* Validate incoming request */
+ efi_status_t status = check_name_terminator(var->Name, var->NameSize);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = check_capabilities(var);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ /* Find an existing entry in the variable index or add a new one */
+ struct variable_info *info =
+ variable_index_find(&context->variable_index, &var->Guid, var->NameSize, var->Name);
+
+ if (!info) {
+ /* If it is a delete request and the target does not exist return error */
+ if (var->DataSize) {
+ info = variable_index_add_entry(&context->variable_index, &var->Guid,
+ var->NameSize, var->Name);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!info)
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Control access */
+ status = check_access_permitted_on_set(context, info, var);
+
+ if (status == EFI_SUCCESS) {
+ /* Access permitted */
+ if (info->is_variable_set) {
+#if defined(UEFI_AUTH_VAR)
+ /*
+ * Check if the variable needs authentication.
+ * The authentication header is not needed after this point so
+ * it is deleted from the variable.
+ */
+ if (info->metadata.attributes &
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+ status = authenticate_variable(
+ context, (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
+
+ if (status != EFI_SUCCESS)
+ return status;
+ }
+#endif
+
+ /**
+ *
+ * UEFI: Page 245
+ * Setting a data variable with no access attributes
+ * causes it to be deleted.
+ *
+ * UEFI: Page 245
+ * Unless the EFI_VARIABLE_APPEND_WRITE,
+ * EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, or
+ * EFI_VARIABLE_ENHANCED_AUTHENTICATED_WRITE_ACCESS attribute is set,
+ * setting a data variable with zero DataSize specified, causes it to
+ * be deleted.
+ *
+ * UEFI: Page 247
+ * To delete a variable created with the
+ * EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,
+ * SetVariable must be used with attributes matching the existing
+ * variable and the DataSize set to the size of the AuthInfo descriptor.
+ * The Data buffer must contain an instance of the AuthInfo descriptor
+ * which will be validated according to the steps in the appropriate
+ * section above referring to updates of Authenticated variables. An
+ * attempt to delete a variable created with the
+ * EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute for
+ * which the prescribed AuthInfo validation fails or when called using
+ * DataSize of zero will fail with an EFI_SECURITY_VIOLATION status.
+ *
+ * Remarks:
+ * In case of EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, the
+ * authentication header is already removed from the data at this
+ * point, so the size will be zero at this point. That is why this
+ * condition is removed from the check below.
+ */
+
+ if (!(var->Attributes &
+ (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
+ (!(var->Attributes & (EFI_VARIABLE_APPEND_WRITE |
+ EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS)) &&
+ !var->DataSize)) {
+ /* It's a remove operation - for a remove, the variable
+ * data must be removed from the storage backend before
+ * modifying and syncing the variable index. This ensures
+ * that it's never possible for an object to exist within
+ * the storage backend without a corresponding index entry.
+ */
+ remove_variable_data(context, info);
+ variable_index_clear_variable(&context->variable_index, info);
+
+ should_sync_index = (var->Attributes & EFI_VARIABLE_NON_VOLATILE);
+ } else {
+ /**
+ * UEFI: Page 245
+ * If a preexisting variable is rewritten with different attributes,
+ * SetVariable() shall not modify the variable and shall return
+ * EFI_INVALID_PARAMETER. The only exception to this is when
+ * the only attribute differing is EFI_VARIABLE_APPEND_WRITE.
+ */
+ if ((info->metadata.attributes | EFI_VARIABLE_APPEND_WRITE) !=
+ (var->Attributes | EFI_VARIABLE_APPEND_WRITE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* It's a set operation where variable data is potentially
+ * being overwritten or extended.
+ */
+ if ((var->Attributes & ~EFI_VARIABLE_APPEND_WRITE) !=
+ info->metadata.attributes) {
+ /* Modifying attributes is forbidden */
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ } else {
+#if defined(UEFI_AUTH_VAR)
+ /*
+ * Check if the variable needs authentication.
+ * The authentication header is not needed after this point so
+ * it is deleted from the variable.
+ */
+ if (var->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+ status = authenticate_variable(
+ context, (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
+
+ if (status != EFI_SUCCESS)
+ return status;
+ }
+#endif
+
+ if (var->DataSize) {
+ /* It's a request to create a new variable */
+ variable_index_set_variable(info, var->Attributes);
+ should_sync_index = (var->Attributes & EFI_VARIABLE_NON_VOLATILE);
+ } else {
+ /* Attempting to remove a non-existent variable
+ * This part shall never be reached, because covered in
+ * earlier check. Left here for safety reasons.
+ */
+ EMSG("Attempting to remove a non-existent variable");
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ /* The order of these operations is important. For an update
+ * or create operation, The variable index is always synchronized
+ * to NV storage first, then the variable data is stored. If the
+ * data store operation fails or doesn't happen due to a power failure,
+ * the inconistency between the variable index and the persistent
+ * store is detectable and may be corrected by purging the corresponding
+ * index entry.
+ */
+ if (should_sync_index)
+ status = sync_variable_index(context);
+
+ /* Store any variable data to the storage backend */
+ if (info->is_variable_set && (status == EFI_SUCCESS))
+ status = store_variable_data(context, info, var);
+ }
+
+ variable_index_remove_unused_entry(&context->variable_index, info);
+
+ return status;
+}
+
+efi_status_t uefi_variable_store_get_variable(const struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
+ size_t max_data_len, size_t *total_length)
+{
+ efi_status_t status = check_name_terminator(var->Name, var->NameSize);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = EFI_NOT_FOUND;
+ *total_length = 0;
+
+ const struct variable_info *info =
+ variable_index_find(&context->variable_index, &var->Guid, var->NameSize, var->Name);
+
+ if (info && info->is_variable_set) {
+ /* Variable already exists */
+ status = check_access_permitted(context, info);
+
+ if (status == EFI_SUCCESS) {
+ status = load_variable_data(context, info, var, max_data_len);
+ var->Attributes = info->metadata.attributes;
+
+ if (status == EFI_SUCCESS)
+ *total_length =
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_TOTAL_SIZE(var);
+ else if (status == EFI_BUFFER_TOO_SMALL)
+ *total_length =
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
+ }
+ }
+
+ return status;
+}
+
+efi_status_t
+uefi_variable_store_get_next_variable_name(const struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *cur,
+ size_t max_name_len, size_t *total_length)
+{
+ efi_status_t status = check_name_terminator(cur->Name, cur->NameSize);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ *total_length = 0;
+
+ while (1) {
+ const struct variable_info *info = variable_index_find_next(
+ &context->variable_index, &cur->Guid, cur->NameSize, cur->Name, &status);
+
+ if (info && (status == EFI_SUCCESS)) {
+ if (info->metadata.name_size <= max_name_len) {
+ cur->Guid = info->metadata.guid;
+ cur->NameSize = info->metadata.name_size;
+ memcpy(cur->Name, info->metadata.name, info->metadata.name_size);
+
+ *total_length =
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_TOTAL_SIZE(
+ cur);
+
+ /*
+ * Check if variable is accessible (e.g boot variable is not
+ * accessible at runtime)
+ */
+ status = check_access_permitted(context, info);
+
+ if (status == EFI_SUCCESS)
+ break;
+ } else {
+ status = EFI_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ } else {
+ /* Do not hide original error if there is any */
+ if (status == EFI_SUCCESS)
+ status = EFI_NOT_FOUND;
+ break;
+ }
+ }
+
+ /* If we found no accessible variable clear the fields for security */
+ if (status != EFI_SUCCESS) {
+ memset(cur->Name, 0, max_name_len);
+ memset(&cur->Guid, 0, sizeof(EFI_GUID));
+ cur->NameSize = 0;
+ }
+
+ return status;
+}
+
+efi_status_t
+uefi_variable_store_query_variable_info(const struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *var_info)
+{
+ struct delegate_variable_store *delegate_store =
+ select_delegate_store(context, var_info->Attributes);
+
+ size_t total_used =
+ space_used(context, var_info->Attributes, delegate_store->storage_backend);
+
+ var_info->MaximumVariableSize = delegate_store->max_variable_size;
+ var_info->MaximumVariableStorageSize = delegate_store->total_capacity;
+ var_info->RemainingVariableStorageSize =
+ (total_used < delegate_store->total_capacity) ?
+ delegate_store->total_capacity - total_used :
+ 0;
+
+ return EFI_SUCCESS;
+}
+
+efi_status_t uefi_variable_store_exit_boot_service(struct uefi_variable_store *context)
+{
+ context->is_boot_service = false;
+ return EFI_SUCCESS;
+}
+
+efi_status_t uefi_variable_store_set_var_check_property(
+ struct uefi_variable_store *context,
+ const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *property)
+{
+ efi_status_t status = check_name_terminator(property->Name, property->NameSize);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ /* Find in index or create a new entry */
+ struct variable_info *info = variable_index_find(&context->variable_index, &property->Guid,
+ property->NameSize, property->Name);
+
+ if (!info) {
+ info = variable_index_add_entry(&context->variable_index, &property->Guid,
+ property->NameSize, property->Name);
+
+ if (!info)
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Applying check constraints to an existing variable that may have
+ * constraints already set. These could constrain the setting of
+ * the constraints.
+ */
+ struct variable_constraints constraints = info->check_constraints;
+
+ status = variable_checker_set_constraints(&constraints, info->is_constraints_set,
+ &property->VariableProperty);
+
+ if (status == EFI_SUCCESS)
+ variable_index_set_constraints(info, &constraints);
+
+ variable_index_remove_unused_entry(&context->variable_index, info);
+
+ return status;
+}
+
+efi_status_t uefi_variable_store_get_var_check_property(
+ struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *property)
+{
+ efi_status_t status = check_name_terminator(property->Name, property->NameSize);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = EFI_NOT_FOUND;
+
+ const struct variable_info *info = variable_index_find(
+ &context->variable_index, &property->Guid, property->NameSize, property->Name);
+
+ if (info && info->is_constraints_set) {
+ variable_checker_get_constraints(&info->check_constraints,
+ &property->VariableProperty);
+
+ status = EFI_SUCCESS;
+ }
+
+ return status;
+}
+
+static void load_variable_index(struct uefi_variable_store *context)
+{
+ struct storage_backend *persistent_store = context->persistent_store.storage_backend;
+
+ if (persistent_store) {
+ size_t data_len = 0;
+
+ psa_status_t psa_status = persistent_store->interface->get(
+ persistent_store->context, context->owner_id,
+ SMM_VARIABLE_INDEX_STORAGE_UID, 0, context->index_sync_buffer_size,
+ context->index_sync_buffer, &data_len);
+
+ if (psa_status == PSA_SUCCESS) {
+ variable_index_restore(&context->variable_index, data_len,
+ context->index_sync_buffer);
+ }
+ }
+}
+
+static efi_status_t sync_variable_index(const struct uefi_variable_store *context)
+{
+ efi_status_t status = EFI_SUCCESS;
+
+ /* Sync the variable index to storage if anything is dirty */
+ size_t data_len = 0;
+
+ bool is_dirty = variable_index_dump(&context->variable_index,
+ context->index_sync_buffer_size,
+ context->index_sync_buffer, &data_len);
+
+ if (is_dirty) {
+ struct storage_backend *persistent_store =
+ context->persistent_store.storage_backend;
+
+ if (persistent_store) {
+ psa_status_t psa_status = persistent_store->interface->set(
+ persistent_store->context, context->owner_id,
+ SMM_VARIABLE_INDEX_STORAGE_UID, data_len,
+ context->index_sync_buffer, PSA_STORAGE_FLAG_NONE);
+
+ status = psa_to_efi_storage_status(psa_status);
+ }
+ }
+
+ return status;
+}
+
+/* Check attribute usage rules */
+static efi_status_t check_capabilities(const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
+{
+ /**
+ * UEFI: Page 245
+ * Runtime access to a data variable implies boot service access. Attributes that
+ * have EFI_VARIABLE_RUNTIME_ACCESS set must also have EFI_VARIABLE_BOOTSERVICE_ACCESS
+ * set.
+ */
+ if ((var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
+ !(var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /**
+ * UEFI: Page 245
+ * EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated and should not be used.
+ * Platforms should return EFI_UNSUPPORTED if a caller to SetVariable() specifies this
+ * attribute.
+ */
+ if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+ return EFI_UNSUPPORTED;
+
+ /**
+ * UEFI: Page 246
+ * If both the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS and the
+ * EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS attribute are set in a
+ * SetVariable() call, then the firmware must return EFI_INVALID_PARAMETER.
+ */
+ if ((var->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) &&
+ (var->Attributes & EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS))
+ return EFI_INVALID_PARAMETER;
+
+ /* EFI_VARIABLE_AUTHENTICATION_3 is not supported by trusted-services */
+ if (var->Attributes & EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS)
+ return EFI_UNSUPPORTED;
+
+ /* A non existing attribute setting has been requested */
+ if (var->Attributes & ~EFI_VARIABLE_MASK)
+ return EFI_UNSUPPORTED;
+
+ /* EFI_VARIABLE_HARDWARE_ERROR_RECORD is not supported */
+ if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ return EFI_UNSUPPORTED;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * UEFI: Page 237
+ * If EFI_BOOT_SERVICES.ExitBootServices() has already been executed, data variables
+ * without the EFI_VARIABLE_RUNTIME_ACCESS attribute set will not be visible to GetVariable()
+ * and will return an EFI_NOT_FOUND error.
+ */
+static efi_status_t check_access_permitted(const struct uefi_variable_store *context,
+ const struct variable_info *info)
+{
+ efi_status_t status = EFI_SUCCESS;
+
+ if (info->is_variable_set && (info->metadata.attributes & (EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS))) {
+ /* Access is controlled */
+ status = EFI_NOT_FOUND;
+
+ if (context->is_boot_service) {
+ if (info->metadata.attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
+ status = EFI_SUCCESS;
+ } else {
+ if (info->metadata.attributes & EFI_VARIABLE_RUNTIME_ACCESS)
+ status = EFI_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+static efi_status_t
+check_access_permitted_on_set(const struct uefi_variable_store *context,
+ const struct variable_info *info,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
+{
+ efi_status_t status = check_access_permitted(context, info);
+
+ if ((status == EFI_SUCCESS) && info->is_constraints_set) {
+ /* Apply check constraints */
+ status = variable_checker_check_on_set(&info->check_constraints, var->Attributes,
+ var->DataSize);
+ }
+
+ return status;
+}
+
+#if defined(UEFI_AUTH_VAR)
+/*
+ * Returns whether the two guid-s equal. To avoid structure padding related error
+ * the fields are checked separately instead of memcmp.
+ */
+static bool compare_guid(const EFI_GUID *guid1, const EFI_GUID *guid2)
+{
+ return guid1->Data1 == guid2->Data1 && guid1->Data2 == guid2->Data2 &&
+ guid1->Data3 == guid2->Data3 &&
+ !memcmp(&guid1->Data4, &guid2->Data4, sizeof(guid1->Data4));
+}
+
+/*
+ * Creates a "map" that contains pointers to some of the fields of the SMM variable and the
+ * UEFI variable stored in the SMM data field. This way a variable is parsed only once.
+ */
+static bool init_efi_data_map(const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
+ bool with_auth_hdr, efi_data_map *map)
+{
+ bool is_valid = false;
+
+ EFI_GUID pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID;
+
+ if (var && map) {
+ map->smm_variable = var;
+
+ map->smm_variable_data =
+ (uint8_t *)var + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
+
+ if (with_auth_hdr) {
+ map->efi_auth_descriptor =
+ (EFI_VARIABLE_AUTHENTICATION_2 *)map->smm_variable_data;
+
+ if (var->DataSize < EFI_VARIABLE_AUTHENTICATION_2_SIZE_WITHOUT_CERTDATA)
+ return false;
+
+ if (ADD_OVERFLOW(sizeof(map->efi_auth_descriptor->TimeStamp),
+ map->efi_auth_descriptor->AuthInfo.Hdr.dwLength,
+ &map->efi_auth_descriptor_len)) {
+ EMSG("Auth descriptor overflow (TimeStamp - dwLength)");
+ return false;
+ }
+
+ if (map->efi_auth_descriptor_len > var->DataSize) {
+ EMSG("auth descriptor is longer than the max variable size");
+ return false;
+ }
+
+ if (SUB_OVERFLOW(map->efi_auth_descriptor->AuthInfo.Hdr.dwLength,
+ sizeof(map->efi_auth_descriptor->AuthInfo.Hdr),
+ &map->efi_auth_descriptor_certdata_len)) {
+ EMSG("Auth descriptor overflow (dwLength - Hdr)");
+ return false;
+ }
+
+ if (SUB_OVERFLOW(map->efi_auth_descriptor_certdata_len,
+ sizeof(map->efi_auth_descriptor->AuthInfo.CertType),
+ &map->efi_auth_descriptor_certdata_len)) {
+ EMSG("Auth descriptor overflow (dwLength - Hdr - CertType)");
+ return false;
+ }
+
+ if (map->efi_auth_descriptor_certdata_len > var->DataSize) {
+ EMSG("auth descriptor certdata field is longer than the max variable size");
+ return false;
+ }
+
+ if (ADD_OVERFLOW((uintptr_t)(map->efi_auth_descriptor),
+ map->efi_auth_descriptor_len,
+ (uintptr_t *)(&map->payload))) {
+ EMSG("auth descriptor overflow");
+ return false;
+ }
+
+ if (SUB_OVERFLOW(map->smm_variable->DataSize, map->efi_auth_descriptor_len,
+ &map->payload_len)) {
+ EMSG("Payload length overflow");
+ return false;
+ }
+
+ if (map->payload_len > map->smm_variable->DataSize) {
+ EMSG("auth descriptor certdata field is longer than the max variable size");
+ return false;
+ }
+
+ /**
+ * Check a viable auth descriptor is present at start of variable data
+ * and that certificates and the signature are of the right type.
+ *
+ * UEFI: Page 253
+ * 1. Verify that the correct AuthInfo.CertType (EFI_CERT_TYPE_PKCS7_GUID)
+ * has been used and that the AuthInfo.CertData value parses correctly as a
+ * PKCS #7 SignedData value
+ */
+ if (map->smm_variable->DataSize >= map->efi_auth_descriptor_len &&
+ map->efi_auth_descriptor->AuthInfo.Hdr.wRevision ==
+ WIN_CERT_CURRENT_VERSION &&
+ map->efi_auth_descriptor->AuthInfo.Hdr.wCertificateType ==
+ WIN_CERT_TYPE_EFI_GUID &&
+ compare_guid(&pkcs7_guid,
+ &map->efi_auth_descriptor->AuthInfo.CertType)) {
+ /*
+ * If it the descriptor fits, determine the
+ * start and length of certificate data
+ */
+ if (map->smm_variable->DataSize >= map->efi_auth_descriptor_len) {
+ /* The certificate buffer follows the fixed sized header */
+ uintptr_t cert_data_offset =
+ (size_t)map->efi_auth_descriptor->AuthInfo.CertData -
+ (size_t)map->smm_variable_data;
+
+ if (map->efi_auth_descriptor_len >= cert_data_offset)
+ is_valid = true;
+ }
+ }
+ } else {
+ map->payload = map->smm_variable_data;
+ map->payload_len = map->smm_variable->DataSize;
+ is_valid = true;
+ }
+
+ if (is_valid) {
+ /*
+ * In case of key variables the payload is also
+ * accessible as a signature list
+ */
+ if (compare_name_to_key_store_name(var->Name, var->NameSize,
+ EFI_PLATFORM_KEY_NAME,
+ sizeof(EFI_PLATFORM_KEY_NAME)) ||
+ compare_name_to_key_store_name(var->Name, var->NameSize,
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ sizeof(EFI_KEY_EXCHANGE_KEY_NAME)) ||
+ compare_name_to_key_store_name(var->Name, var->NameSize,
+ EFI_IMAGE_SECURITY_DATABASE,
+ sizeof(EFI_IMAGE_SECURITY_DATABASE)) ||
+ compare_name_to_key_store_name(var->Name, var->NameSize,
+ EFI_IMAGE_SECURITY_DATABASE1,
+ sizeof(EFI_IMAGE_SECURITY_DATABASE1))) {
+ map->efi_signature_list = (EFI_SIGNATURE_LIST *)map->payload;
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Creates an SMM variable that can be passed to GetVariable call to be filled with the
+ * data from the store.
+ */
+static void create_smm_variable(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE **variable,
+ size_t name_size, size_t data_size, const uint8_t *name,
+ EFI_GUID *guid)
+{
+ /*
+ * name_size: Length of the name array in bytes.
+ * (*variable)->NameSize: Length of (*variable)->Name array in bytes.
+ */
+
+ if (name && guid) {
+ *variable = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)malloc(
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, data_size));
+
+ if (*variable) {
+ (*variable)->NameSize = name_size;
+ (*variable)->DataSize = data_size;
+
+ memcpy(&(*variable)->Guid, guid, sizeof(EFI_GUID));
+ memcpy(&(*variable)->Name, name, name_size);
+ }
+ } else {
+ *variable = NULL;
+ }
+}
+
+/**
+ * UEFI: Page 252
+ * Hash the serialization of the values of the VariableName, VendorGuid and Attributes
+ * parameters of the SetVariable() call and the TimeStamp component of the
+ * EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable’s new value (i.e.
+ * the Data parameter’s new variable content). That is, digest = hash (VariableName, VendorGuid,
+ * Attributes, TimeStamp, DataNew_variable_content). The NULL character terminating the
+ * VariableName value shall not be included in the hash computation.
+ */
+static bool calc_variable_hash(const efi_data_map *var_map, uint8_t *hash_buffer,
+ size_t hash_buffer_size, size_t *hash_len)
+{
+ psa_hash_operation_t op = psa_hash_operation_init();
+
+ if (psa_hash_setup(&op, PSA_ALG_SHA_256) != PSA_SUCCESS)
+ return false;
+
+ /* Skip the NULL character at the end! */
+ int status = psa_hash_update(&op, (const uint8_t *)var_map->smm_variable->Name,
+ var_map->smm_variable->NameSize - sizeof(uint16_t));
+
+ if (!status)
+ status = psa_hash_update(&op, (const uint8_t *)&var_map->smm_variable->Guid,
+ sizeof(EFI_GUID));
+
+ if (!status)
+ status = psa_hash_update(&op, (const uint8_t *)&var_map->smm_variable->Attributes,
+ sizeof(var_map->smm_variable->Attributes));
+
+ if (!status)
+ status = psa_hash_update(&op,
+ (const uint8_t *)&var_map->efi_auth_descriptor->TimeStamp,
+ sizeof(EFI_TIME));
+
+ if (!status)
+ status = psa_hash_update(&op, (const uint8_t *)var_map->payload,
+ var_map->payload_len);
+
+ if (!status)
+ status = psa_hash_finish(&op, hash_buffer, hash_buffer_size, hash_len);
+
+ if (!status)
+ return true;
+
+ psa_hash_abort(&op);
+ return false;
+}
+
+static efi_status_t
+select_verification_keys(const efi_data_map new_var, EFI_GUID global_variable_guid,
+ EFI_GUID security_database_guid, uint64_t maximum_variable_size,
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE **allowed_key_store_variables)
+{
+ /**
+ * UEFI: Page 254
+ * 5. If the variable is the global PK variable or the global KEK variable,
+ * verify that the signature has been made with the current Platform Key.
+ */
+ if (compare_name_to_key_store_name(new_var.smm_variable->Name,
+ new_var.smm_variable->NameSize, EFI_PLATFORM_KEY_NAME,
+ sizeof(EFI_PLATFORM_KEY_NAME))) {
+ /* This variable must have global guid */
+ if (!compare_guid(&new_var.smm_variable->Guid, &global_variable_guid))
+ return EFI_SECURITY_VIOLATION;
+
+ /*
+ * PK is verified by itself if exists. In case of an empty PK,
+ * the verification shall be skipped.
+ */
+ create_smm_variable(&(allowed_key_store_variables[0]),
+ sizeof(EFI_PLATFORM_KEY_NAME), maximum_variable_size,
+ (uint8_t *)EFI_PLATFORM_KEY_NAME, &global_variable_guid);
+ } else if (compare_name_to_key_store_name(
+ new_var.smm_variable->Name, new_var.smm_variable->NameSize,
+ EFI_KEY_EXCHANGE_KEY_NAME, sizeof(EFI_KEY_EXCHANGE_KEY_NAME))) {
+ /* This variable must have global guid */
+ if (!compare_guid(&new_var.smm_variable->Guid, &global_variable_guid))
+ return EFI_SECURITY_VIOLATION;
+
+ /* KEK must be verified by PK */
+ create_smm_variable(&(allowed_key_store_variables[0]),
+ sizeof(EFI_PLATFORM_KEY_NAME), maximum_variable_size,
+ (uint8_t *)EFI_PLATFORM_KEY_NAME, &global_variable_guid);
+ }
+ /**
+ * UEFI: Page 254:
+ * 5. If the variable is the “db”, “dbt”, “dbr”, or “dbx” variable mentioned
+ * in step 3, verify that the signer’s certificate chains to a certificate in the Key
+ * Exchange Key database (or that the signature was made with the current Platform Key).
+ */
+ else if (compare_name_to_key_store_name(
+ new_var.smm_variable->Name, new_var.smm_variable->NameSize,
+ EFI_IMAGE_SECURITY_DATABASE, sizeof(EFI_IMAGE_SECURITY_DATABASE)) ||
+ compare_name_to_key_store_name(
+ new_var.smm_variable->Name, new_var.smm_variable->NameSize,
+ EFI_IMAGE_SECURITY_DATABASE1, sizeof(EFI_IMAGE_SECURITY_DATABASE1)) ||
+ compare_name_to_key_store_name(
+ new_var.smm_variable->Name, new_var.smm_variable->NameSize,
+ EFI_IMAGE_SECURITY_DATABASE2, sizeof(EFI_IMAGE_SECURITY_DATABASE2)) ||
+ compare_name_to_key_store_name(
+ new_var.smm_variable->Name, new_var.smm_variable->NameSize,
+ EFI_IMAGE_SECURITY_DATABASE3, sizeof(EFI_IMAGE_SECURITY_DATABASE3))) {
+ /* This variable must have global guid */
+ if (!compare_guid(&new_var.smm_variable->Guid, &security_database_guid))
+ return EFI_SECURITY_VIOLATION;
+
+ /* Databases can be verified by either KEK or PK */
+ create_smm_variable(&(allowed_key_store_variables[0]),
+ sizeof(EFI_PLATFORM_KEY_NAME), maximum_variable_size,
+ (uint8_t *)EFI_PLATFORM_KEY_NAME, &global_variable_guid);
+
+ create_smm_variable(&(allowed_key_store_variables[1]),
+ sizeof(EFI_KEY_EXCHANGE_KEY_NAME), maximum_variable_size,
+ (uint8_t *)EFI_KEY_EXCHANGE_KEY_NAME, &global_variable_guid);
+ } else {
+ /*
+ * Any other variable is considered Private Authenticated Variable.
+ * These are verified by db
+ */
+ create_smm_variable(&(allowed_key_store_variables[0]),
+ sizeof(EFI_IMAGE_SECURITY_DATABASE), maximum_variable_size,
+ (uint8_t *)EFI_IMAGE_SECURITY_DATABASE,
+ &security_database_guid);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*
+ * Verifies the signature of an authenticated variable by another variable.
+ * Only key variables that has a special payload(PK, KEK, db, dbx, dbr, dbt) can verify signature.
+ */
+static efi_status_t verify_var_by_key_var(const efi_data_map *new_var,
+ const efi_data_map *key_store_var,
+ const uint8_t *hash_buffer, size_t hash_len)
+{
+ EFI_GUID cert_x509_guid = EFI_CERT_X509_GUID;
+
+ const EFI_SIGNATURE_LIST *current_signature_list = key_store_var->efi_signature_list;
+
+ /* Initialized to the size of the payload and decreased by the processed data */
+ size_t remaining_data = key_store_var->payload_len;
+
+ /* Iterate through the signature lists */
+ while ((remaining_data > 0) &&
+ (remaining_data >= current_signature_list->SignatureListSize)) {
+ /*
+ * Check if the GUID of the signature list is properly set
+ * TODO: Only X509 certificate based signature list is supported
+ */
+ if (compare_guid(&current_signature_list->SignatureType, &cert_x509_guid)) {
+ EFI_SIGNATURE_DATA *current_signature =
+ (EFI_SIGNATURE_DATA *)((uint8_t *)current_signature_list +
+ sizeof(EFI_SIGNATURE_LIST) +
+ current_signature_list->SignatureHeaderSize);
+
+ size_t number_of_signatures =
+ (current_signature_list->SignatureListSize -
+ sizeof(EFI_SIGNATURE_LIST) -
+ current_signature_list->SignatureHeaderSize) /
+ current_signature_list->SignatureSize;
+
+ /* Iterate through the certificates in the current signature list */
+ for (int index = 0; index < number_of_signatures; index++) {
+ uint8_t *next_certificate = current_signature->SignatureData;
+
+ size_t next_certificate_size =
+ current_signature_list->SignatureSize -
+ sizeof(current_signature->SignatureOwner);
+
+ if (verify_pkcs7_signature(
+ new_var->efi_auth_descriptor->AuthInfo.CertData,
+ new_var->efi_auth_descriptor_certdata_len, hash_buffer,
+ hash_len, next_certificate, next_certificate_size) == 0)
+
+ return EFI_SUCCESS;
+
+ /* Switch to the next certificate */
+ current_signature =
+ (EFI_SIGNATURE_DATA *)((uint8_t *)current_signature +
+ current_signature_list
+ ->SignatureSize);
+ }
+ } else {
+ /* Wrong guid */
+ return EFI_INVALID_PARAMETER;
+ }
+
+ remaining_data -= current_signature_list->SignatureListSize;
+ current_signature_list =
+ (EFI_SIGNATURE_LIST *)((uint8_t *)current_signature_list +
+ current_signature_list->SignatureListSize);
+ }
+
+ /* None of the entries verifies the new variable */
+ return EFI_SECURITY_VIOLATION;
+}
+
+/* Basic verification of the authentication header of the new variable.
+ * First finds the key variable responsible for the authentication of the new variable,
+ * then verifies it.
+ */
+static efi_status_t authenticate_variable(const struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
+{
+ efi_status_t status = EFI_SUCCESS;
+ EFI_GUID pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID;
+ EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE;
+ EFI_GUID security_database_guid = EFI_IMAGE_SECURITY_DATABASE_GUID;
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO variable_info = { 0, 0, 0, 0 };
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *pk_variable = NULL;
+ size_t pk_payload_size = 0;
+ efi_data_map var_map = { NULL, NULL, NULL, 0, 0, NULL, 0, NULL };
+ uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
+ size_t hash_len = 0;
+ bool hash_result = false;
+
+ /* Create a map of the fields of the new variable including the auth header */
+ if (!init_efi_data_map(var, true, &var_map))
+ return EFI_SECURITY_VIOLATION;
+
+ /* database variables can be verified by either PK or KEK while images
+ * should be checked by db and dbx so the length of two will be enough.
+ */
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *allowed_key_store_variables[] = { NULL, NULL };
+
+ /* Find the maximal size of variables for the GetVariable operation */
+ status = uefi_variable_store_query_variable_info(context, &variable_info);
+ if (status != EFI_SUCCESS)
+ return EFI_SECURITY_VIOLATION;
+
+ /**
+ * UEFI: Page 253
+ * 3. If the variable SetupMode==1, and the variable is a secure
+ * boot policy variable, then the firmware implementation shall
+ * consider the checks in the following steps 4 and 5 to have
+ * passed, and proceed with updating the variable value as
+ * outlined below.
+ *
+ * While no Platform Key is enrolled, the SetupMode variable shall
+ * be equal to 1. While SetupMode == 1, the platform firmware shall
+ * not require authentication in order to modify the Platform Key,
+ * Key Enrollment Key, OsRecoveryOrder, OsRecovery####,
+ * and image security databases.
+ *
+ * After the Platform Key is enrolled, the SetupMode variable shall
+ * be equal to 0. While SetupMode == 0, the platform firmware shall
+ * require authentication in order to modify the Platform Key,
+ * Key Enrollment Key, OsRecoveryOrder, OsRecovery####,
+ * and image security databases
+ *
+ * NOTE: SetupMode variable is not supported yet, so the
+ * Platform Key is checked to enable or disable authentication.
+ */
+ create_smm_variable(&pk_variable, sizeof(EFI_PLATFORM_KEY_NAME),
+ variable_info.MaximumVariableSize, (uint8_t *)EFI_PLATFORM_KEY_NAME,
+ &global_variable_guid);
+
+ if (!pk_variable)
+ return EFI_OUT_OF_RESOURCES;
+
+ status = uefi_variable_store_get_variable(
+ context, pk_variable, variable_info.MaximumVariableSize, &pk_payload_size);
+
+ /* If PK does not exist authentication is disabled */
+ if (status != EFI_SUCCESS) {
+ free(pk_variable);
+ status = EFI_SUCCESS;
+ goto end;
+ }
+
+ /*
+ * Get the size of the PK payload with the help of a variable map before freeing the object.
+ * pk_var_map points to fields of pk_variable so this code part is in a separate code block
+ * to eliminate the var map right after freeing pk_variable. This way we can avoid
+ * unexpected access to freed memory area.
+ */
+ {
+ efi_data_map pk_var_map;
+
+ /* Authentication header is not stored, so don't search for it! */
+ if (!init_efi_data_map(pk_variable, false, &pk_var_map)) {
+ free(pk_variable);
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ pk_payload_size = pk_var_map.payload_len;
+ free(pk_variable);
+ }
+
+ /* If PK exists, but is empty the authentication is disabled */
+ if (pk_payload_size == 0) {
+ status = EFI_SUCCESS;
+ goto end;
+ }
+
+ /**
+ * UEFI: Page 246
+ * If the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set in a
+ * SetVariable() call, and firmware does not support signature type of the certificate
+ * included in the EFI_VARIABLE_AUTHENTICATION_2 descriptor, then the SetVariable() call
+ * shall return EFI_INVALID_PARAMETER. The list of signature types supported by the
+ * firmware is defined by the SignatureSupport variable. Signature type of the certificate
+ * is defined by its digest and encryption algorithms.
+ */
+ /* TODO: Should support WIN_CERT_TYPE_PKCS_SIGNED_DATA and WIN_CERT_TYPE_EFI_PKCS115 */
+ if (var_map.efi_auth_descriptor->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID)
+ return EFI_INVALID_PARAMETER;
+
+ /* Only a CertType of EFI_CERT_TYPE_PKCS7_GUID is accepted */
+ if (!compare_guid(&var_map.efi_auth_descriptor->AuthInfo.CertType, &pkcs7_guid))
+ return EFI_SECURITY_VIOLATION;
+
+ /**
+ * Time associated with the authentication descriptor. For the TimeStamp value,
+ * components Pad1, Nanosecond, TimeZone, Daylight and Pad2 shall be set to 0.
+ * This means that the time shall always be expressed in GMT.
+ *
+ * UEFI: Page 253
+ * 2. Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components
+ * of the TimeStamp value are set to zero. Unless the EFI_VARIABLE_APPEND_WRITE
+ * attribute is set, verify that the TimeStamp value is later than the current
+ * timestamp value associated with the variable
+ */
+ if ((var_map.efi_auth_descriptor->TimeStamp.Pad1 != 0) ||
+ (var_map.efi_auth_descriptor->TimeStamp.Pad2 != 0) ||
+ (var_map.efi_auth_descriptor->TimeStamp.Nanosecond != 0) ||
+ (var_map.efi_auth_descriptor->TimeStamp.TimeZone != 0) ||
+ (var_map.efi_auth_descriptor->TimeStamp.Daylight != 0)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ /* Calculate hash for the variable only once */
+ hash_result = calc_variable_hash(&var_map, (uint8_t *)&hash_buffer, sizeof(hash_buffer),
+ &hash_len);
+
+ if (!hash_result) {
+ status = EFI_SECURITY_VIOLATION;
+ goto end;
+ }
+
+ status = select_verification_keys(var_map, global_variable_guid, security_database_guid,
+ variable_info.MaximumVariableSize,
+ &allowed_key_store_variables[0]);
+
+ if (status != EFI_SUCCESS)
+ goto end;
+
+ for (int i = 0; i < ARRAY_SIZE(allowed_key_store_variables); i++) {
+ size_t actual_variable_length = 0; /* Unused */
+ efi_data_map allowed_key_store_var_map;
+
+ if (!allowed_key_store_variables[i])
+ continue;
+
+ status = uefi_variable_store_get_variable(context, allowed_key_store_variables[i],
+ variable_info.MaximumVariableSize,
+ &actual_variable_length);
+
+ if (status) {
+ /* When the parent does not exist it is considered verification failure */
+ if (status == EFI_NOT_FOUND)
+ status = EFI_SECURITY_VIOLATION;
+ goto end;
+ }
+
+ /* Create a map of the variable fields for easier access */
+ if (!init_efi_data_map(allowed_key_store_variables[i], false,
+ &allowed_key_store_var_map)) {
+ status = EFI_SECURITY_VIOLATION;
+ goto end;
+ }
+
+ status = verify_var_by_key_var(&var_map, &allowed_key_store_var_map,
+ (uint8_t *)&hash_buffer, hash_len);
+
+ if (status == EFI_SUCCESS)
+ goto end;
+ }
+
+end:
+ /* Cleanup heap */
+ for (int i = 0; i < ARRAY_SIZE(allowed_key_store_variables); i++) {
+ if (allowed_key_store_variables[i])
+ free(allowed_key_store_variables[i]);
+ }
+
+ /* Remove the authentication header from the variable if the authentication is successful */
+ if (status == EFI_SUCCESS) {
+ uint8_t *smm_payload =
+ (uint8_t *)var + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
+
+ memmove(smm_payload, var_map.payload, var_map.payload_len);
+ memset((uint8_t *)smm_payload + var_map.payload_len, 0,
+ var_map.efi_auth_descriptor_len);
+
+ var->DataSize -= var_map.efi_auth_descriptor_len;
+ }
+
+ return status;
+}
+#endif
+
+static efi_status_t store_variable_data(const struct uefi_variable_store *context,
+ const struct variable_info *info,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
+{
+ psa_status_t psa_status = PSA_SUCCESS;
+ size_t data_len = var->DataSize;
+ const uint8_t *data =
+ (const uint8_t *)var + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
+
+ struct delegate_variable_store *delegate_store =
+ select_delegate_store(context, info->metadata.attributes);
+
+ if (delegate_store->storage_backend) {
+ if (!(var->Attributes & EFI_VARIABLE_APPEND_WRITE)) {
+ /* Create or overwrite variable data */
+ psa_status = store_overwrite(delegate_store, context->owner_id,
+ info->metadata.uid, data_len, data);
+ } else {
+ /**
+ * UEFI: Page 246
+ * If the EFI_VARIABLE_APPEND_WRITE attribute is set in a SetVariable()
+ * call, then any existing variable value shall be appended with the
+ * value of the Data parameter. If the firmware does not support the
+ * append operation, then the SetVariable() call shall return
+ * EFI_INVALID_PARAMETER.
+ */
+ psa_status = store_append_write(delegate_store, context->owner_id,
+ info->metadata.uid, data_len, data);
+ }
+ }
+
+ if ((psa_status != PSA_SUCCESS) && delegate_store->is_nv) {
+ /* A storage failure has occurred so attempt to fix any
+ * mismatch between the variable index and stored NV variables.
+ */
+ purge_orphan_index_entries(context);
+ }
+
+ return psa_to_efi_storage_status(psa_status);
+}
+
+static efi_status_t remove_variable_data(const struct uefi_variable_store *context,
+ const struct variable_info *info)
+{
+ psa_status_t psa_status = PSA_SUCCESS;
+
+ if (info->is_variable_set) {
+ struct delegate_variable_store *delegate_store =
+ select_delegate_store(context, info->metadata.attributes);
+
+ if (delegate_store->storage_backend) {
+ psa_status = delegate_store->storage_backend->interface->remove(
+ delegate_store->storage_backend->context, context->owner_id,
+ info->metadata.uid);
+ }
+ }
+
+ return psa_to_efi_storage_status(psa_status);
+}
+
+static efi_status_t load_variable_data(const struct uefi_variable_store *context,
+ const struct variable_info *info,
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
+ size_t max_data_len)
+{
+ psa_status_t psa_status = PSA_SUCCESS;
+ uint8_t *data = (uint8_t *)var + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
+
+ struct delegate_variable_store *delegate_store =
+ select_delegate_store(context, info->metadata.attributes);
+
+ if (delegate_store->storage_backend) {
+ struct psa_storage_info_t storage_info;
+
+ psa_status = delegate_store->storage_backend->interface->get_info(
+ delegate_store->storage_backend->context, context->owner_id,
+ info->metadata.uid, &storage_info);
+
+ if (psa_status == PSA_SUCCESS) {
+ size_t get_limit = (var->DataSize < max_data_len) ? var->DataSize :
+ max_data_len;
+
+ if (get_limit >= storage_info.size) {
+ size_t got_len = 0;
+
+ psa_status = delegate_store->storage_backend->interface->get(
+ delegate_store->storage_backend->context, context->owner_id,
+ info->metadata.uid, 0, storage_info.size, data, &got_len);
+
+ var->DataSize = got_len;
+ } else {
+ var->DataSize = storage_info.size;
+ psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ }
+ }
+
+ return psa_to_efi_storage_status(psa_status);
+}
+
+static psa_status_t store_overwrite(struct delegate_variable_store *delegate_store,
+ uint32_t client_id, uint64_t uid, size_t data_length,
+ const void *data)
+{
+ /* Police maximum variable size limit */
+ if (data_length > delegate_store->max_variable_size)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ psa_status_t psa_status = delegate_store->storage_backend->interface->set(
+ delegate_store->storage_backend->context, client_id, uid, data_length, data,
+ PSA_STORAGE_FLAG_NONE);
+
+ return psa_status;
+}
+
+static psa_status_t store_append_write(struct delegate_variable_store *delegate_store,
+ uint32_t client_id, uint64_t uid, size_t data_length,
+ const void *data)
+{
+ struct psa_storage_info_t storage_info;
+
+ if (data_length == 0)
+ return PSA_SUCCESS;
+
+ psa_status_t psa_status = delegate_store->storage_backend->interface->get_info(
+ delegate_store->storage_backend->context, client_id, uid, &storage_info);
+
+ if (psa_status != PSA_SUCCESS)
+ return psa_status;
+
+ /* Determine size of appended variable */
+ size_t new_size = storage_info.size + data_length;
+
+ /* Defend against integer overflow */
+ if (new_size < storage_info.size)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ /* Police maximum variable size limit */
+ if (new_size > delegate_store->max_variable_size)
+ return PSA_ERROR_INVALID_ARGUMENT;
+
+ /* Storage backend doesn't support an append operation so we need
+ * to read the current variable data, extend it and write it back.
+ */
+ uint8_t *rw_buf = malloc(new_size);
+
+ if (!rw_buf)
+ return PSA_ERROR_INSUFFICIENT_MEMORY;
+
+ size_t old_size = 0;
+
+ psa_status = delegate_store->storage_backend->interface->get(
+ delegate_store->storage_backend->context, client_id, uid, 0, new_size, rw_buf,
+ &old_size);
+
+ if (psa_status == PSA_SUCCESS) {
+ if ((old_size + data_length) <= new_size) {
+ /* Extend the variable data */
+ memcpy(&rw_buf[old_size], data, data_length);
+
+ psa_status = delegate_store->storage_backend->interface->set(
+ delegate_store->storage_backend->context, client_id, uid,
+ old_size + data_length, rw_buf, storage_info.flags);
+ } else {
+ /* There's a mismatch between the length obtained from
+ * get_info() and the subsequent length returned by get().
+ */
+ psa_status = PSA_ERROR_STORAGE_FAILURE;
+ }
+ }
+
+ free(rw_buf);
+
+ return psa_status;
+}
+
+static void purge_orphan_index_entries(const struct uefi_variable_store *context)
+{
+ bool any_orphans = false;
+ struct variable_index_iterator iter;
+
+ variable_index_iterator_first(&iter, &context->variable_index);
+
+ /* Iterate over variable index looking for any entries for NV
+ * variables where there is no corresponding object in the
+ * persistent store. This condition could arise due to
+ * a power failure before an object is stored.
+ */
+ while (!variable_index_iterator_is_done(&iter)) {
+ struct variable_info *info = variable_index_iterator_current(&iter);
+
+ if (info->is_variable_set &&
+ (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
+ struct psa_storage_info_t storage_info;
+ struct storage_backend *storage_backend =
+ context->persistent_store.storage_backend;
+
+ psa_status_t psa_status = storage_backend->interface->get_info(
+ storage_backend->context, context->owner_id, info->metadata.uid,
+ &storage_info);
+
+ if (psa_status != PSA_SUCCESS) {
+ /* Detected a mismatch between the index and storage */
+ variable_index_clear_variable(&context->variable_index, info);
+ any_orphans = true;
+ }
+ }
+
+ variable_index_iterator_next(&iter);
+ }
+
+ if (any_orphans)
+ sync_variable_index(context);
+}
+
+static struct delegate_variable_store *
+select_delegate_store(const struct uefi_variable_store *context, uint32_t attributes)
+{
+ bool is_nv = (attributes & EFI_VARIABLE_NON_VOLATILE);
+
+ return (is_nv) ? (struct delegate_variable_store *)&context->persistent_store :
+ (struct delegate_variable_store *)&context->volatile_store;
+}
+
+static size_t space_used(const struct uefi_variable_store *context, uint32_t attributes,
+ struct storage_backend *storage_backend)
+{
+ if (!storage_backend)
+ return 0;
+
+ size_t total_used = 0;
+ struct variable_index_iterator iter;
+
+ variable_index_iterator_first(&iter, &context->variable_index);
+
+ while (!variable_index_iterator_is_done(&iter)) {
+ struct variable_info *info = variable_index_iterator_current(&iter);
+
+ if (info->is_variable_set &&
+ ((info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE) ==
+ (attributes & EFI_VARIABLE_NON_VOLATILE))) {
+ struct psa_storage_info_t storage_info;
+
+ psa_status_t psa_status = storage_backend->interface->get_info(
+ storage_backend->context, context->owner_id, info->metadata.uid,
+ &storage_info);
+
+ if (psa_status == PSA_SUCCESS)
+ total_used += storage_info.size;
+ }
+
+ variable_index_iterator_next(&iter);
+ }
+
+ return total_used;
+}
+
+static efi_status_t psa_to_efi_storage_status(psa_status_t psa_status)
+{
+ efi_status_t efi_status = EFI_DEVICE_ERROR;
+
+ switch (psa_status) {
+ case PSA_SUCCESS:
+ efi_status = EFI_SUCCESS;
+ break;
+ case PSA_ERROR_NOT_PERMITTED:
+ efi_status = EFI_ACCESS_DENIED;
+ break;
+ case PSA_ERROR_INVALID_ARGUMENT:
+ efi_status = EFI_INVALID_PARAMETER;
+ break;
+ case PSA_ERROR_BAD_STATE:
+ efi_status = EFI_NOT_READY;
+ break;
+ case PSA_ERROR_BUFFER_TOO_SMALL:
+ efi_status = EFI_BUFFER_TOO_SMALL;
+ break;
+ case PSA_ERROR_DOES_NOT_EXIST:
+ efi_status = EFI_NOT_FOUND;
+ break;
+ case PSA_ERROR_INSUFFICIENT_MEMORY:
+ efi_status = EFI_OUT_OF_RESOURCES;
+ break;
+ case PSA_ERROR_INSUFFICIENT_STORAGE:
+ efi_status = EFI_OUT_OF_RESOURCES;
+ break;
+ case PSA_ERROR_STORAGE_FAILURE:
+ efi_status = EFI_DEVICE_ERROR;
+ break;
+ case PSA_STATUS_HARDWARE_FAILURE:
+ efi_status = EFI_DEVICE_ERROR;
+ break;
+ default:
+ break;
+ }
+
+ return efi_status;
+}
+
+static efi_status_t check_name_terminator(const int16_t *name, size_t name_size)
+{
+ /* Variable names must be null terminated */
+ if (name_size < sizeof(int16_t) || name[name_size / sizeof(int16_t) - 1] != u'\0')
+ return EFI_INVALID_PARAMETER;
+
+ return EFI_SUCCESS;
+}
+
+#if defined(UEFI_AUTH_VAR)
+/* Compares SMM variable name to key variable name. */
+static bool compare_name_to_key_store_name(const int16_t *name1, size_t size1,
+ const uint16_t *name2, size_t size2)
+{
+ if (!name1 || !name2)
+ return false;
+ if (size1 != size2)
+ return false;
+
+ return memcmp((void *)name1, (void *)name2, size1) == 0;
+}
+#endif
diff --git a/components/service/smm_variable/backend/uefi_variable_store.h b/components/service/uefi/smm_variable/backend/uefi_variable_store.h
index fe0f24af4..dc3d3cae2 100644
--- a/components/service/smm_variable/backend/uefi_variable_store.h
+++ b/components/service/uefi/smm_variable/backend/uefi_variable_store.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -8,12 +8,13 @@
#ifndef UEFI_VARIABLE_STORE_H
#define UEFI_VARIABLE_STORE_H
-#include <stdbool.h>
-#include <stdint.h>
-#include <stddef.h>
#include <protocols/common/efi/efi_status.h>
#include <protocols/service/smm_variable/smm_variable_proto.h>
#include <service/secure_storage/backend/storage_backend.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include "variable_index.h"
#ifdef __cplusplus
@@ -21,22 +22,34 @@ extern "C" {
#endif
/**
+ * \brief delegate_variable_store structure definition
+ *
+ * A delegate_variable_store combines an association with a concrete
+ * storage backend and a set of limits parameters.
+ */
+struct delegate_variable_store {
+ bool is_nv;
+ size_t total_capacity;
+ size_t max_variable_size;
+ struct storage_backend *storage_backend;
+};
+
+/**
* \brief uefi_variable_store structure definition
*
* A uefi_variable_store provides a variable store using a persistent and a
* volatile storage backend. The persistent storage backend may be realized
- * by another trusted service such as the ptotected storage or internal trusted
+ * by another trusted service such as the protected storage or internal trusted
* storage service.
*/
-struct uefi_variable_store
-{
+struct uefi_variable_store {
bool is_boot_service;
uint32_t owner_id;
uint8_t *index_sync_buffer;
size_t index_sync_buffer_size;
struct variable_index variable_index;
- struct storage_backend *persistent_store;
- struct storage_backend *volatile_store;
+ struct delegate_variable_store persistent_store;
+ struct delegate_variable_store volatile_store;
};
/**
@@ -54,20 +67,32 @@ struct uefi_variable_store
*
* @return EFI_SUCCESS if initialized successfully
*/
-efi_status_t uefi_variable_store_init(
- struct uefi_variable_store *context,
- uint32_t owner_id,
- size_t max_variables,
- struct storage_backend *persistent_store,
- struct storage_backend *volatile_store);
+efi_status_t uefi_variable_store_init(struct uefi_variable_store *context, uint32_t owner_id,
+ size_t max_variables,
+ struct storage_backend *persistent_store,
+ struct storage_backend *volatile_store);
/**
* @brief De-initialises a uefi_variable_store
*
* @param[in] context uefi_variable_store instance
*/
-void uefi_variable_store_deinit(
- struct uefi_variable_store *context);
+void uefi_variable_store_deinit(struct uefi_variable_store *context);
+
+/**
+ * @brief Set storage limits
+ *
+ * Overrides the default limits for the specified storage space. These
+ * values are reflected in the values returned by QueryVariableInfo.
+ *
+ * @param[in] context uefi_variable_store instance
+ * @param[in] attributes EFI_VARIABLE_NON_VOLATILE or 0
+ * @param[in] total_capacity The total storage capacity in bytes
+ * @param[in] max_variable_size Variable size limit
+ */
+void uefi_variable_store_set_storage_limits(const struct uefi_variable_store *context,
+ uint32_t attributes, size_t total_capacity,
+ size_t max_variable_size);
/**
* @brief Set variable
@@ -77,11 +102,10 @@ void uefi_variable_store_deinit(
* @param[in] context uefi_variable_store instance
* @param[in] var The 'access variable' structure
*
- * @return EFI_SUCCESS if succesful
+ * @return EFI_SUCCESS if successful
*/
-efi_status_t uefi_variable_store_set_variable(
- struct uefi_variable_store *context,
- const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
+efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *context,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
/**
* @brief Get variable
@@ -93,13 +117,11 @@ efi_status_t uefi_variable_store_set_variable(
* @param[in] max_data_len The maximum variable data length
* @param[out] total_len The total length of the header + data
*
- * @return EFI_SUCCESS if succesful
+ * @return EFI_SUCCESS if successful
*/
-efi_status_t uefi_variable_store_get_variable(
- struct uefi_variable_store *context,
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
- size_t max_data_len,
- size_t *total_length);
+efi_status_t uefi_variable_store_get_variable(const struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
+ size_t max_data_len, size_t *total_length);
/**
* @brief Get next variable name
@@ -111,25 +133,24 @@ efi_status_t uefi_variable_store_get_variable(
* @param[in] max_name_len The maximum variable name length
* @param[out] total_len The total length of the output
*
- * @return EFI_SUCCESS if succesful
+ * @return EFI_SUCCESS if successful
*/
-efi_status_t uefi_variable_store_get_next_variable_name(
- struct uefi_variable_store *context,
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *cur,
- size_t max_name_len,
- size_t *total_length);
+efi_status_t
+uefi_variable_store_get_next_variable_name(const struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *cur,
+ size_t max_name_len, size_t *total_length);
/**
* @brief Query for variable info
*
* @param[in] context uefi_variable_store instance
- * @param[out] info Returns info
+ * @param[inout] var_info Returns info
*
- * @return EFI_SUCCESS if succesful
+ * @return EFI_SUCCESS if successful
*/
-efi_status_t uefi_variable_store_query_variable_info(
- struct uefi_variable_store *context,
- SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *cur);
+efi_status_t
+uefi_variable_store_query_variable_info(const struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *var_info);
/**
* @brief Exit boot service
@@ -139,10 +160,9 @@ efi_status_t uefi_variable_store_query_variable_info(
*
* @param[in] context uefi_variable_store instance
*
- * @return EFI_SUCCESS if succesful
+ * @return EFI_SUCCESS if successful
*/
-efi_status_t uefi_variable_store_exit_boot_service(
- struct uefi_variable_store *context);
+efi_status_t uefi_variable_store_exit_boot_service(struct uefi_variable_store *context);
/**
* @brief Set variable check property
@@ -152,7 +172,7 @@ efi_status_t uefi_variable_store_exit_boot_service(
* @param[in] context uefi_variable_store instance
* @param[in] property The variable check property
*
- * @return EFI_SUCCESS if succesful
+ * @return EFI_SUCCESS if successful
*/
efi_status_t uefi_variable_store_set_var_check_property(
struct uefi_variable_store *context,
@@ -166,7 +186,7 @@ efi_status_t uefi_variable_store_set_var_check_property(
* @param[in] context uefi_variable_store instance
* @param[out] property The variable check property
*
- * @return EFI_SUCCESS if succesful
+ * @return EFI_SUCCESS if successful
*/
efi_status_t uefi_variable_store_get_var_check_property(
struct uefi_variable_store *context,
diff --git a/components/service/smm_variable/backend/variable_checker.c b/components/service/uefi/smm_variable/backend/variable_checker.c
index 81a41d01c..e26b0d165 100644
--- a/components/service/smm_variable/backend/variable_checker.c
+++ b/components/service/uefi/smm_variable/backend/variable_checker.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -7,10 +7,9 @@
#include "variable_checker.h"
-efi_status_t variable_checker_set_constraints(
- struct variable_constraints *constraints,
- bool is_update,
- const VAR_CHECK_VARIABLE_PROPERTY *check_var_property)
+efi_status_t variable_checker_set_constraints(struct variable_constraints *constraints,
+ bool is_update,
+ const VAR_CHECK_VARIABLE_PROPERTY *check_var_property)
{
/* Sanity check input parameters */
if (check_var_property->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION)
@@ -19,14 +18,6 @@ efi_status_t variable_checker_set_constraints(
if (check_var_property->MinSize > check_var_property->MaxSize)
return EFI_INVALID_PARAMETER;
- /* Check for an attempt to undo previously set access constraints */
- if (is_update) {
-
- if ((constraints->property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) &&
- !(check_var_property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY))
- return EFI_INVALID_PARAMETER;
- }
-
/* New check constraints accepted */
constraints->revision = check_var_property->Revision;
constraints->attributes = check_var_property->Attributes;
@@ -37,9 +28,8 @@ efi_status_t variable_checker_set_constraints(
return EFI_SUCCESS;
}
-void variable_checker_get_constraints(
- const struct variable_constraints *constraints,
- VAR_CHECK_VARIABLE_PROPERTY *check_var_property)
+void variable_checker_get_constraints(const struct variable_constraints *constraints,
+ VAR_CHECK_VARIABLE_PROPERTY *check_var_property)
{
check_var_property->Revision = constraints->revision;
check_var_property->Attributes = constraints->attributes;
@@ -48,11 +38,11 @@ void variable_checker_get_constraints(
check_var_property->MaxSize = constraints->max_size;
}
-efi_status_t variable_checker_check_on_set(
- const struct variable_constraints *constraints,
- uint32_t attributes,
- size_t data_size)
+efi_status_t variable_checker_check_on_set(const struct variable_constraints *constraints,
+ uint32_t attributes, size_t data_size)
{
+ (void)attributes;
+
if (constraints->property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
return EFI_WRITE_PROTECTED;
diff --git a/components/service/smm_variable/backend/variable_checker.h b/components/service/uefi/smm_variable/backend/variable_checker.h
index cd623a39d..6a5c36db9 100644
--- a/components/service/smm_variable/backend/variable_checker.h
+++ b/components/service/uefi/smm_variable/backend/variable_checker.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -8,11 +8,11 @@
#ifndef VARIABLE_CHECKER_H
#define VARIABLE_CHECKER_H
+#include <protocols/common/efi/efi_status.h>
+#include <protocols/service/smm_variable/smm_variable_proto.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
-#include <protocols/common/efi/efi_status.h>
-#include <protocols/service/smm_variable/smm_variable_proto.h>
#ifdef __cplusplus
extern "C" {
@@ -25,13 +25,12 @@ extern "C" {
* based on policy driven constraints, set using:
* SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET.
*/
-struct variable_constraints
-{
- uint16_t revision;
- uint16_t property;
- uint32_t attributes;
- size_t min_size;
- size_t max_size;
+struct variable_constraints {
+ uint16_t revision;
+ uint16_t property;
+ uint32_t attributes;
+ size_t min_size;
+ size_t max_size;
};
/**
@@ -43,10 +42,9 @@ struct variable_constraints
*
* @return EFI_SUCCESS if check constraints set successfully
*/
-efi_status_t variable_checker_set_constraints(
- struct variable_constraints *constraints,
- bool is_update,
- const VAR_CHECK_VARIABLE_PROPERTY *check_var_property);
+efi_status_t
+variable_checker_set_constraints(struct variable_constraints *constraints, bool is_update,
+ const VAR_CHECK_VARIABLE_PROPERTY *check_var_property);
/**
* @brief Get variable check constraints
@@ -54,9 +52,8 @@ efi_status_t variable_checker_set_constraints(
* @param[in] constraints Variable constraints to get
* @param[out] check_var_property The result
*/
-void variable_checker_get_constraints(
- const struct variable_constraints *constraints,
- VAR_CHECK_VARIABLE_PROPERTY *check_var_property);
+void variable_checker_get_constraints(const struct variable_constraints *constraints,
+ VAR_CHECK_VARIABLE_PROPERTY *check_var_property);
/**
* @brief Check if set operations is allowed
@@ -67,10 +64,8 @@ void variable_checker_get_constraints(
*
* @return EFI_SUCCESS if set is allowed
*/
-efi_status_t variable_checker_check_on_set(
- const struct variable_constraints *constraints,
- uint32_t attributes,
- size_t data_size);
+efi_status_t variable_checker_check_on_set(const struct variable_constraints *constraints,
+ uint32_t attributes, size_t data_size);
#ifdef __cplusplus
}
diff --git a/components/service/uefi/smm_variable/backend/variable_index.c b/components/service/uefi/smm_variable/backend/variable_index.c
new file mode 100644
index 000000000..d850dbe18
--- /dev/null
+++ b/components/service/uefi/smm_variable/backend/variable_index.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "variable_index.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Private functions */
+static uint64_t name_hash(const EFI_GUID *guid, size_t name_size, const int16_t *name)
+{
+ /* Using djb2 hash by Dan Bernstein */
+ uint64_t hash = 5381;
+
+ /* Calculate hash over GUID */
+ hash = ((hash << 5) + hash) + guid->Data1;
+ hash = ((hash << 5) + hash) + guid->Data2;
+ hash = ((hash << 5) + hash) + guid->Data3;
+
+ for (int i = 0; i < 8; ++i) {
+ hash = ((hash << 5) + hash) + guid->Data4[i];
+ }
+
+ /* Extend to cover name up to but not including null terminator */
+ for (size_t i = 0; i < (name_size - sizeof(int16_t)) / sizeof(int16_t); ++i) {
+ hash = ((hash << 5) + hash) + name[i];
+ }
+
+ return hash;
+}
+
+static uint64_t generate_uid(const struct variable_index *context, const EFI_GUID *guid,
+ size_t name_size, const int16_t *name)
+{
+ uint64_t uid = name_hash(guid, name_size, name);
+
+ /* todo - handle collision */
+ (void)context;
+
+ return uid;
+}
+
+static int find_variable(const struct variable_index *context, const EFI_GUID *guid,
+ size_t name_size, const int16_t *name)
+{
+ int found_pos = -1;
+ uint64_t uid = name_hash(guid, name_size, name);
+
+ for (size_t pos = 0; pos < context->max_variables; pos++) {
+ if ((context->entries[pos].in_use) &&
+ (uid == context->entries[pos].info.metadata.uid)) {
+ found_pos = pos;
+ break;
+ }
+ }
+
+ return found_pos;
+}
+
+static int find_free(const struct variable_index *context)
+{
+ int free_pos = -1;
+
+ for (size_t pos = 0; pos < context->max_variables; pos++) {
+ if (!context->entries[pos].in_use) {
+ free_pos = pos;
+ break;
+ }
+ }
+
+ return free_pos;
+}
+
+static void mark_dirty(struct variable_entry *entry)
+{
+ if (entry->info.metadata.attributes & EFI_VARIABLE_NON_VOLATILE)
+ entry->dirty = true;
+}
+
+static struct variable_entry *containing_entry(const struct variable_info *info)
+{
+ size_t info_offset = offsetof(struct variable_entry, info);
+ struct variable_entry *entry = (struct variable_entry *)((uint8_t *)info - info_offset);
+ return entry;
+}
+
+/* Public functions */
+efi_status_t variable_index_init(struct variable_index *context, size_t max_variables)
+{
+ context->max_variables = max_variables;
+ context->entries =
+ (struct variable_entry *)malloc(sizeof(struct variable_entry) * max_variables);
+
+ if (context->entries) {
+ memset(context->entries, 0, sizeof(struct variable_entry) * max_variables);
+ }
+
+ return (context->entries) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
+}
+
+void variable_index_deinit(struct variable_index *context)
+{
+ free(context->entries);
+}
+
+size_t variable_index_max_dump_size(struct variable_index *context)
+{
+ return sizeof(struct variable_metadata) * context->max_variables;
+}
+
+struct variable_info *variable_index_find(const struct variable_index *context,
+ const EFI_GUID *guid, size_t name_size,
+ const int16_t *name)
+{
+ struct variable_info *result = NULL;
+ int pos = find_variable(context, guid, name_size, name);
+
+ if (pos >= 0) {
+ result = &context->entries[pos].info;
+ }
+
+ return result;
+}
+
+struct variable_info *variable_index_find_next(const struct variable_index *context,
+ const EFI_GUID *guid, size_t name_size,
+ const int16_t *name, efi_status_t *status)
+{
+ struct variable_info *result = NULL;
+ *status = EFI_NOT_FOUND;
+
+ if (name_size >= sizeof(int16_t)) {
+ /*
+ * Name must be at least one character long to accommodate
+ * the mandatory null terminator.
+ */
+ if (name[0] != 0) {
+ /* Find next from current name */
+ int pos = find_variable(context, guid, name_size, name);
+
+ if (pos >= 0) {
+ /* Iterate to next used entry */
+ ++pos;
+ while (pos < (int)context->max_variables) {
+ if (context->entries[pos].in_use &&
+ context->entries[pos].info.is_variable_set) {
+ result = &context->entries[pos].info;
+ *status = EFI_SUCCESS;
+ break;
+ }
+
+ ++pos;
+ }
+ } else {
+ /* A non-empty name was provided but it wasn't found */
+ *status = EFI_INVALID_PARAMETER;
+ }
+ } else {
+ /* Find first */
+ int pos = 0;
+
+ while (pos < (int)context->max_variables) {
+ if (context->entries[pos].in_use &&
+ context->entries[pos].info.is_variable_set) {
+ result = &context->entries[pos].info;
+ *status = EFI_SUCCESS;
+ break;
+ }
+
+ ++pos;
+ }
+ }
+ }
+
+ return result;
+}
+
+static struct variable_entry *add_entry(const struct variable_index *context, const EFI_GUID *guid,
+ size_t name_size, const int16_t *name)
+{
+ struct variable_entry *entry = NULL;
+
+ if (name_size <= (VARIABLE_INDEX_MAX_NAME_SIZE * sizeof(int16_t))) {
+ int pos = find_free(context);
+
+ if (pos >= 0) {
+ entry = &context->entries[pos];
+
+ struct variable_info *info = &entry->info;
+
+ /* Initialize metadata */
+ info->metadata.uid = generate_uid(context, guid, name_size, name);
+ info->metadata.guid = *guid;
+ info->metadata.attributes = 0;
+ info->metadata.name_size = name_size;
+ memcpy(info->metadata.name, name, name_size);
+
+ info->is_constraints_set = false;
+ info->is_variable_set = false;
+
+ entry->in_use = true;
+ }
+ }
+
+ return entry;
+}
+
+struct variable_info *variable_index_add_entry(const struct variable_index *context,
+ const EFI_GUID *guid, size_t name_size,
+ const int16_t *name)
+{
+ struct variable_info *info = NULL;
+ struct variable_entry *entry = add_entry(context, guid, name_size, name);
+
+ if (entry) {
+ info = &entry->info;
+ }
+
+ return info;
+}
+
+void variable_index_remove_unused_entry(const struct variable_index *context,
+ struct variable_info *info)
+{
+ (void)context;
+
+ if (info && !info->is_constraints_set && !info->is_variable_set) {
+ struct variable_entry *entry = containing_entry(info);
+ entry->in_use = false;
+
+ memset(info, 0, sizeof(struct variable_info));
+ }
+}
+
+void variable_index_set_variable(struct variable_info *info, uint32_t attributes)
+{
+ struct variable_entry *entry = containing_entry(info);
+
+ info->metadata.attributes = attributes;
+ info->is_variable_set = true;
+
+ mark_dirty(entry);
+}
+
+void variable_index_clear_variable(const struct variable_index *context, struct variable_info *info)
+{
+ (void)context;
+
+ if (info) {
+ struct variable_entry *entry = containing_entry(info);
+ mark_dirty(entry);
+
+ /* Mark variable as no longer set */
+ entry->info.is_variable_set = false;
+ }
+}
+
+void variable_index_set_constraints(struct variable_info *info,
+ const struct variable_constraints *constraints)
+{
+ if (info) {
+ info->check_constraints = *constraints;
+ info->is_constraints_set = true;
+ }
+}
+
+bool variable_index_dump(const struct variable_index *context, size_t buffer_size, uint8_t *buffer,
+ size_t *data_len)
+{
+ bool any_dirty = false;
+ uint8_t *dump_pos = buffer;
+ size_t bytes_dumped = 0;
+
+ for (size_t pos = 0; pos < context->max_variables; pos++) {
+ struct variable_entry *entry = &context->entries[pos];
+ struct variable_metadata *metadata = &entry->info.metadata;
+
+ if (entry->in_use && entry->info.is_variable_set &&
+ (metadata->attributes & EFI_VARIABLE_NON_VOLATILE) &&
+ ((bytes_dumped + sizeof(struct variable_metadata)) <= buffer_size)) {
+ memcpy(dump_pos, metadata, sizeof(struct variable_metadata));
+ bytes_dumped += sizeof(struct variable_metadata);
+ dump_pos += sizeof(struct variable_metadata);
+ }
+
+ any_dirty |= entry->dirty;
+ entry->dirty = false;
+ }
+
+ *data_len = bytes_dumped;
+
+ return any_dirty;
+}
+
+size_t variable_index_restore(const struct variable_index *context, size_t data_len,
+ const uint8_t *buffer)
+{
+ size_t bytes_loaded = 0;
+ const uint8_t *load_pos = buffer;
+ int pos = 0;
+
+ while (bytes_loaded < data_len) {
+ if ((data_len - bytes_loaded) >= sizeof(struct variable_metadata)) {
+ struct variable_entry *entry = &context->entries[pos];
+ struct variable_metadata *metadata = &entry->info.metadata;
+
+ memcpy(metadata, load_pos, sizeof(struct variable_metadata));
+
+ entry->info.is_variable_set = true;
+ entry->in_use = true;
+
+ bytes_loaded += sizeof(struct variable_metadata);
+ load_pos += sizeof(struct variable_metadata);
+
+ ++pos;
+ } else {
+ /* Not a whole number of variable_metadata structs! */
+ break;
+ }
+ }
+
+ return bytes_loaded;
+}
diff --git a/components/service/smm_variable/backend/variable_index.h b/components/service/uefi/smm_variable/backend/variable_index.h
index e109d0d19..5d3b7a7c6 100644
--- a/components/service/smm_variable/backend/variable_index.h
+++ b/components/service/uefi/smm_variable/backend/variable_index.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -8,11 +8,12 @@
#ifndef VARIABLE_INDEX_H
#define VARIABLE_INDEX_H
+#include <protocols/common/efi/efi_status.h>
+#include <protocols/service/smm_variable/smm_variable_proto.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
-#include <protocols/common/efi/efi_status.h>
-#include <protocols/service/smm_variable/smm_variable_proto.h>
+
#include "variable_checker.h"
#ifdef __cplusplus
@@ -22,20 +23,19 @@ extern "C" {
/**
* Implementation limits
*/
-#define VARIABLE_INDEX_MAX_NAME_SIZE (32)
+#define VARIABLE_INDEX_MAX_NAME_SIZE (64)
/**
* \brief variable_metadata structure definition
*
* Holds metadata associated with stored variable.
*/
-struct variable_metadata
-{
- EFI_GUID guid;
- size_t name_size;
- int16_t name[VARIABLE_INDEX_MAX_NAME_SIZE];
- uint32_t attributes;
- uint64_t uid;
+struct variable_metadata {
+ EFI_GUID guid;
+ size_t name_size;
+ int16_t name[VARIABLE_INDEX_MAX_NAME_SIZE];
+ uint32_t attributes;
+ uint64_t uid;
};
/**
@@ -43,8 +43,7 @@ struct variable_metadata
*
* Holds information about a stored variable.
*/
-struct variable_info
-{
+struct variable_info {
struct variable_metadata metadata;
struct variable_constraints check_constraints;
@@ -57,12 +56,11 @@ struct variable_info
*
* Represents a store variable in the variable index.
*/
-struct variable_entry
-{
- struct variable_info info;
+struct variable_entry {
+ struct variable_info info;
- bool in_use;
- bool dirty;
+ bool in_use;
+ bool dirty;
};
/**
@@ -71,8 +69,7 @@ struct variable_entry
* Provides an index of stored variables to allow the uefi variable store
* contents to be enumerated.
*/
-struct variable_index
-{
+struct variable_index {
size_t max_variables;
struct variable_entry *entries;
};
@@ -85,17 +82,14 @@ struct variable_index
*
* @return EFI_SUCCESS if initialized successfully
*/
-efi_status_t variable_index_init(
- struct variable_index *context,
- size_t max_variables);
+efi_status_t variable_index_init(struct variable_index *context, size_t max_variables);
/**
* @brief De-initialises a variable_index
*
* @param[in] context variable_index
*/
-void variable_index_deinit(
- struct variable_index *context);
+void variable_index_deinit(struct variable_index *context);
/**
* @brief Returns the maximum dump size
@@ -106,8 +100,7 @@ void variable_index_deinit(
*
* @param[in] context variable_index
*/
-size_t variable_index_max_dump_size(
- struct variable_index *context);
+size_t variable_index_max_dump_size(struct variable_index *context);
/**
* @brief Find info about a variable
@@ -119,11 +112,9 @@ size_t variable_index_max_dump_size(
*
* @return Pointer to variable_info or NULL
*/
-const struct variable_info *variable_index_find(
- const struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name);
+struct variable_info *variable_index_find(const struct variable_index *context,
+ const EFI_GUID *guid, size_t name_size,
+ const int16_t *name);
/**
* @brief Find the next variable in the index
@@ -132,82 +123,72 @@ const struct variable_info *variable_index_find(
* @param[in] guid The variable's guid
* @param[in] name_size The name parameter's size
* @param[in] name The variable's name
+ * @param[out] status Provides error status
*
* @return Pointer to variable_info or NULL
*/
-const struct variable_info *variable_index_find_next(
- const struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name);
+struct variable_info *variable_index_find_next(const struct variable_index *context,
+ const EFI_GUID *guid, size_t name_size,
+ const int16_t *name, efi_status_t *status);
/**
- * @brief Add a new variable to the index
+ * @brief Add a new entry to the index
+ *
+ * An entry is needed either when a new variable is created or
+ * when variable constraints are set for a variable that doesn't
+ * yet exist.
*
* @param[in] context variable_index
* @param[in] guid The variable's guid
* @param[in] name_size The name parameter's size
* @param[in] name The variable's name
- * @param[in] attributes The variable's attributes
*
* @return Pointer to variable_info or NULL
*/
-const struct variable_info *variable_index_add_variable(
- struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name,
- uint32_t attributes);
+struct variable_info *variable_index_add_entry(const struct variable_index *context,
+ const EFI_GUID *guid, size_t name_size,
+ const int16_t *name);
/**
- * @brief Remove a variable from the index
+ * @brief Remove an unused entry from the index
*
- * Removes a variable from the index if it exists.
+ * Removes an entry if it is not in use.
*
* @param[in] context variable_index
* @param[in] info The variable info corresponding to the entry to remove
*/
-void variable_index_remove_variable(
- struct variable_index *context,
- const struct variable_info *info);
+void variable_index_remove_unused_entry(const struct variable_index *context,
+ struct variable_info *info);
/**
- * @brief Update a variable that's already in the index
+ * @brief Set a variable to the index
+ *
+ * An entry for the variable must already exist.
*
* @param[in] info variable info
* @param[in] attributes The variable's attributes
*/
-void variable_index_update_variable(
- const struct variable_info *info,
- uint32_t attributes);
+void variable_index_set_variable(struct variable_info *info, uint32_t attributes);
/**
- * @brief Add a new check constraints object to the index
+ * @brief Clear a variable from the index
*
- * @param[in] context variable_index
- * @param[in] guid The variable's guid
- * @param[in] name_size The name parameter's size
- * @param[in] name The variable's name
- * @param[in] constraints The check constraints
+ * Clears a variable from the index
*
- * @return Pointer to variable_info or NULL
+ * @param[in] context variable_index
+ * @param[in] info The variable info corresponding to the variable to clear
*/
-const struct variable_info *variable_index_add_constraints(
- struct variable_index *context,
- const EFI_GUID *guid,
- size_t name_size,
- const int16_t *name,
- const struct variable_constraints *constraints);
+void variable_index_clear_variable(const struct variable_index *context,
+ struct variable_info *info);
/**
- * @brief Update variable constraints that are already in the index
+ * @brief Set a check constraints object associated with a variavle
*
* @param[in] info variable info
* @param[in] constraints The check constraints
*/
-void variable_index_update_constraints(
- const struct variable_info *info,
- const struct variable_constraints *constraints);
+void variable_index_set_constraints(struct variable_info *info,
+ const struct variable_constraints *constraints);
/**
* @brief Dump the serialized index contents for persistent backup
@@ -219,11 +200,8 @@ void variable_index_update_constraints(
*
* @return True if there is unsaved data
*/
-bool variable_index_dump(
- struct variable_index *context,
- size_t buffer_size,
- uint8_t *buffer,
- size_t *data_len);
+bool variable_index_dump(const struct variable_index *context, size_t buffer_size, uint8_t *buffer,
+ size_t *data_len);
/**
* @brief Restore the serialized index contents
@@ -237,11 +215,8 @@ bool variable_index_dump(
*
* @return Number of bytes loaded
*/
-size_t variable_index_restore(
- const struct variable_index *context,
- size_t data_len,
- const uint8_t *buffer);
-
+size_t variable_index_restore(const struct variable_index *context, size_t data_len,
+ const uint8_t *buffer);
#ifdef __cplusplus
}
diff --git a/components/service/uefi/smm_variable/backend/variable_index_iterator.c b/components/service/uefi/smm_variable/backend/variable_index_iterator.c
new file mode 100644
index 000000000..eb0c118d2
--- /dev/null
+++ b/components/service/uefi/smm_variable/backend/variable_index_iterator.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "variable_index_iterator.h"
+
+#include <stddef.h>
+
+void variable_index_iterator_first(struct variable_index_iterator *iter,
+ const struct variable_index *variable_index)
+{
+ iter->variable_index = variable_index;
+ iter->current_pos = variable_index->max_variables;
+
+ for (size_t pos = 0; pos < variable_index->max_variables; pos++) {
+ if (variable_index->entries[pos].in_use) {
+ iter->current_pos = pos;
+ break;
+ }
+ }
+}
+
+bool variable_index_iterator_is_done(const struct variable_index_iterator *iter)
+{
+ return iter->current_pos >= iter->variable_index->max_variables;
+}
+
+struct variable_info *variable_index_iterator_current(const struct variable_index_iterator *iter)
+{
+ struct variable_info *current = NULL;
+
+ if (!variable_index_iterator_is_done(iter)) {
+ current = &iter->variable_index->entries[iter->current_pos].info;
+ }
+
+ return current;
+}
+
+void variable_index_iterator_next(struct variable_index_iterator *iter)
+{
+ if (iter->current_pos < iter->variable_index->max_variables) {
+ size_t next_pos = iter->current_pos + 1;
+
+ while (next_pos < iter->variable_index->max_variables) {
+ if (iter->variable_index->entries[next_pos].in_use)
+ break;
+
+ ++next_pos;
+ }
+
+ iter->current_pos = next_pos;
+ }
+}
diff --git a/components/service/smm_variable/backend/variable_index_iterator.h b/components/service/uefi/smm_variable/backend/variable_index_iterator.h
index f64a2c49d..0e5df6fb1 100644
--- a/components/service/smm_variable/backend/variable_index_iterator.h
+++ b/components/service/uefi/smm_variable/backend/variable_index_iterator.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -9,6 +9,7 @@
#define VARIABLE_INDEX_ITERATOR_H
#include <stdbool.h>
+
#include "variable_index.h"
#ifdef __cplusplus
@@ -21,8 +22,7 @@ extern "C" {
* Used for iterating over in-use entries held by the associated
* variable_index.
*/
-struct variable_index_iterator
-{
+struct variable_index_iterator {
const struct variable_index *variable_index;
size_t current_pos;
};
@@ -33,9 +33,8 @@ struct variable_index_iterator
* @param[in] iter The iterator
* @param[in] variable_index The associated variable index
*/
-void variable_index_iterator_first(
- struct variable_index_iterator *iter,
- const struct variable_index *variable_index);
+void variable_index_iterator_first(struct variable_index_iterator *iter,
+ const struct variable_index *variable_index);
/**
* @brief Check if iterated beyond last entry
@@ -44,8 +43,7 @@ void variable_index_iterator_first(
*
* @return True if iterating is done
*/
-bool variable_index_iterator_is_done(
- const struct variable_index_iterator *iter);
+bool variable_index_iterator_is_done(const struct variable_index_iterator *iter);
/**
* @brief Return variable info for the current position
@@ -54,17 +52,14 @@ bool variable_index_iterator_is_done(
*
* @return Pointer to variable_info or NULL
*/
-const struct variable_info *variable_index_iterator_current(
- const struct variable_index_iterator *iter);
+struct variable_info *variable_index_iterator_current(const struct variable_index_iterator *iter);
/**
* @brief Iterate to next position
*
* @param[in] iter The iterator
*/
-void variable_index_iterator_next(
- struct variable_index_iterator *iter);
-
+void variable_index_iterator_next(struct variable_index_iterator *iter);
#ifdef __cplusplus
}
diff --git a/components/service/smm_variable/client/cpp/component.cmake b/components/service/uefi/smm_variable/client/cpp/component.cmake
index 0a3155dab..0a3155dab 100644
--- a/components/service/smm_variable/client/cpp/component.cmake
+++ b/components/service/uefi/smm_variable/client/cpp/component.cmake
diff --git a/components/service/uefi/smm_variable/client/cpp/smm_variable_client.cpp b/components/service/uefi/smm_variable/client/cpp/smm_variable_client.cpp
new file mode 100644
index 000000000..f71d0c864
--- /dev/null
+++ b/components/service/uefi/smm_variable/client/cpp/smm_variable_client.cpp
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "smm_variable_client.h"
+
+#include <cstring>
+#include <protocols/rpc/common/packed-c/status.h>
+
+static size_t string_get_size_in_bytes(const std::u16string &string)
+{
+ return string.size() * sizeof(typename std::u16string::value_type);
+}
+
+smm_variable_client::smm_variable_client()
+ : session(NULL)
+ , m_err_rpc_status(RPC_SUCCESS)
+{
+}
+
+smm_variable_client::smm_variable_client(struct rpc_caller_session *session)
+ : session(session)
+ , m_err_rpc_status(RPC_SUCCESS)
+{
+}
+
+smm_variable_client::~smm_variable_client()
+{
+}
+
+std::u16string smm_variable_client::to_variable_name(const char16_t *name) const
+{
+ std::u16string name_var(name);
+ name_var.push_back(0);
+
+ return name_var;
+}
+
+void smm_variable_client::set_caller_session(struct rpc_caller_session *session)
+{
+ this->session = session;
+}
+
+int smm_variable_client::err_rpc_status() const
+{
+ return m_err_rpc_status;
+}
+
+efi_status_t smm_variable_client::set_variable(const EFI_GUID &guid, const char16_t *name,
+ const std::string data, uint32_t attributes)
+{
+ return set_variable(guid, to_variable_name(name), data, attributes, 0, 0);
+}
+
+efi_status_t smm_variable_client::set_variable(const EFI_GUID &guid, const char16_t *name,
+ const unsigned char* data, size_t data_length,
+ uint32_t attributes)
+{
+ std::string data_var((const char *)data, data_length);
+ return set_variable(guid, to_variable_name(name), data_var, attributes, 0, 0);
+}
+
+efi_status_t smm_variable_client::set_variable(const EFI_GUID &guid, const std::u16string &name,
+ const unsigned char *data, size_t data_length,
+ uint32_t attributes)
+{
+ std::string data_string(reinterpret_cast<char const *>(data), data_length);
+
+ return set_variable(guid, name, data_string, attributes, 0, 0);
+}
+
+efi_status_t smm_variable_client::set_variable(const EFI_GUID &guid, const std::u16string &name,
+ const std::string &data, uint32_t attributes)
+{
+ return set_variable(guid, name, data, attributes, 0, 0);
+}
+
+efi_status_t smm_variable_client::set_variable(const EFI_GUID &guid, const std::u16string &name,
+ const std::string &data, uint32_t attributes,
+ size_t override_name_size, size_t override_data_size)
+{
+ efi_status_t efi_status = EFI_NOT_READY;
+ size_t name_size = string_get_size_in_bytes(name);
+ size_t data_size = data.size();
+ size_t req_len = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, data_size);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(session, &req_buf, req_len, 0);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_var =
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)req_buf;
+
+ access_var->Guid = guid;
+ access_var->NameSize = name_size;
+ access_var->DataSize = data_size;
+ access_var->Attributes = attributes;
+
+ memcpy(access_var->Name, name.c_str(), name_size);
+ memcpy(&req_buf[SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_var)],
+ data.data(), data_size);
+
+ /* To support invalid size testing, use overrides if set */
+ if (override_name_size)
+ access_var->NameSize = override_name_size;
+ if (override_data_size)
+ access_var->DataSize = override_data_size;
+
+ m_err_rpc_status = rpc_caller_session_invoke(call_handle,
+ SMM_VARIABLE_FUNCTION_SET_VARIABLE,
+ &resp_buf, &resp_len, &service_status);
+
+ if (m_err_rpc_status == RPC_SUCCESS) {
+ efi_status = service_status;
+ } else {
+ efi_status = rpc_to_efi_status();
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return efi_status;
+}
+
+efi_status_t smm_variable_client::get_variable(const EFI_GUID &guid, const char16_t *name,
+ std::string &data)
+{
+ return get_variable(guid, to_variable_name(name), data, 0, MAX_VAR_DATA_SIZE);
+}
+
+efi_status_t smm_variable_client::get_variable(const EFI_GUID &guid, const char16_t *name,
+ std::string &data, size_t override_name_size,
+ size_t max_data_size)
+{
+ return get_variable(guid, to_variable_name(name), data, override_name_size, max_data_size);
+}
+
+efi_status_t smm_variable_client::get_variable(const EFI_GUID &guid, const std::u16string &name,
+ std::string &data)
+{
+ return get_variable(guid, name, data, 0, MAX_VAR_DATA_SIZE);
+}
+
+efi_status_t smm_variable_client::get_variable(const EFI_GUID &guid, const std::u16string &name,
+ std::string &data, size_t override_name_size,
+ size_t max_data_size)
+{
+ efi_status_t efi_status = EFI_NOT_READY;
+
+ size_t name_size = string_get_size_in_bytes(name);
+ size_t req_len = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, 0);
+ size_t resp_len = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, 0);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(session, &req_buf, req_len, resp_len);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_var =
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)req_buf;
+
+ access_var->Guid = guid;
+ access_var->NameSize = name_size;
+ access_var->DataSize = max_data_size;
+
+ memcpy(access_var->Name, name.c_str(), name_size);
+
+ /* To support invalid size testing, use overrides if set */
+ if (override_name_size)
+ access_var->NameSize = override_name_size;
+
+ m_err_rpc_status = rpc_caller_session_invoke(call_handle,
+ SMM_VARIABLE_FUNCTION_GET_VARIABLE,
+ &resp_buf, &resp_len, &service_status);
+
+ if (m_err_rpc_status == RPC_SUCCESS) {
+ efi_status = service_status;
+
+ if (resp_len >= SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET) {
+ access_var = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)resp_buf;
+ size_t data_size = access_var->DataSize;
+
+ if (resp_len >= SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_TOTAL_SIZE(
+ access_var)) {
+ if (efi_status == EFI_SUCCESS) {
+ const char *data_start = (const char *)&resp_buf
+ [SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(
+ access_var)];
+
+ data.assign(data_start, data_size);
+ }
+ } else if (efi_status == EFI_BUFFER_TOO_SMALL) {
+ data.clear();
+ data.insert(0, data_size, '!');
+ } else {
+ efi_status = EFI_PROTOCOL_ERROR;
+ }
+ }
+ } else {
+ efi_status = rpc_to_efi_status();
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return efi_status;
+}
+
+efi_status_t smm_variable_client::remove_variable(const EFI_GUID &guid, const char16_t *name)
+{
+ return remove_variable(guid, to_variable_name(name));
+}
+
+efi_status_t smm_variable_client::remove_variable(const EFI_GUID &guid, const std::u16string &name)
+{
+ /* Variable is removed by performing a 'set' with zero length data */
+ return set_variable(guid, name, std::string(), 0);
+}
+
+efi_status_t smm_variable_client::get_next_variable_name(EFI_GUID &guid, std::u16string &name)
+{
+ return get_next_variable_name(guid, name, 0);
+}
+
+efi_status_t smm_variable_client::query_variable_info(uint32_t attributes,
+ size_t *max_variable_storage_size,
+ size_t *remaining_variable_storage_size,
+ size_t *max_variable_size)
+{
+ efi_status_t efi_status = EFI_NOT_READY;
+
+ size_t req_len = sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
+ size_t resp_len = sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(session, &req_buf, req_len, resp_len);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *query =
+ (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *)req_buf;
+
+ query->Attributes = attributes;
+ query->MaximumVariableSize = 0;
+ query->MaximumVariableStorageSize = 0;
+ query->RemainingVariableStorageSize = 0;
+
+ m_err_rpc_status = rpc_caller_session_invoke(
+ call_handle, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, &resp_buf,
+ &resp_len, &service_status);
+
+ if (m_err_rpc_status == RPC_SUCCESS) {
+ efi_status = service_status;
+
+ if (efi_status == EFI_SUCCESS) {
+ if (resp_len >=
+ sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
+ query = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *)
+ resp_buf;
+
+ *max_variable_storage_size =
+ query->MaximumVariableStorageSize;
+ *remaining_variable_storage_size =
+ query->RemainingVariableStorageSize;
+ *max_variable_size = query->MaximumVariableSize;
+ } else {
+ efi_status = EFI_PROTOCOL_ERROR;
+ }
+ } else {
+ efi_status = EFI_PROTOCOL_ERROR;
+ }
+ } else {
+ efi_status = rpc_to_efi_status();
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return efi_status;
+}
+
+efi_status_t smm_variable_client::get_next_variable_name(EFI_GUID &guid, std::u16string &name,
+ size_t override_name_size)
+{
+ efi_status_t efi_status = EFI_NOT_READY;
+
+ size_t name_size = string_get_size_in_bytes(name);
+ size_t req_len = SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_SIZE(name_size);
+ size_t resp_len = SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_SIZE(name_size);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(session, &req_buf, req_len, resp_len);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *next_var =
+ (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *)req_buf;
+
+ next_var->Guid = guid;
+ next_var->NameSize = name_size;
+
+ memcpy(next_var->Name, name.c_str(), name_size);
+
+ /* To support invalid size testing, use overrides if set */
+ if (override_name_size)
+ next_var->NameSize = override_name_size;
+
+ m_err_rpc_status = rpc_caller_session_invoke(
+ call_handle, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, &resp_buf,
+ &resp_len, &service_status);
+
+ if (m_err_rpc_status == RPC_SUCCESS) {
+ efi_status = service_status;
+
+ if (efi_status == EFI_SUCCESS) {
+ efi_status = EFI_PROTOCOL_ERROR;
+
+ if (resp_len >=
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET) {
+ next_var =
+ (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *)
+ resp_buf;
+
+ if (resp_len >=
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_TOTAL_SIZE(
+ next_var)) {
+ guid = next_var->Guid;
+ from_variable_name(next_var->Name,
+ next_var->NameSize, name);
+
+ efi_status = EFI_SUCCESS;
+ }
+ }
+ }
+ } else {
+ efi_status = rpc_to_efi_status();
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return efi_status;
+}
+
+efi_status_t smm_variable_client::exit_boot_service()
+{
+ efi_status_t efi_status = EFI_NOT_READY;
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(session, &req_buf, 0, 0);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ m_err_rpc_status = rpc_caller_session_invoke(
+ call_handle, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, &resp_buf, &resp_len,
+ &service_status);
+
+ if (m_err_rpc_status == RPC_SUCCESS) {
+ efi_status = service_status;
+ } else {
+ efi_status = rpc_to_efi_status();
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return efi_status;
+}
+
+efi_status_t smm_variable_client::set_var_check_property(const EFI_GUID &guid, const char16_t *name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property)
+{
+ return set_var_check_property(guid, to_variable_name(name), check_property, 0);
+}
+
+efi_status_t smm_variable_client::set_var_check_property(const EFI_GUID &guid, const char16_t *name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property,
+ size_t override_name_size)
+{
+ return set_var_check_property(guid, to_variable_name(name), check_property,
+ override_name_size);
+}
+
+
+efi_status_t
+smm_variable_client::set_var_check_property(const EFI_GUID &guid, const std::u16string &name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property)
+{
+ return set_var_check_property(guid, name, check_property, 0);
+}
+
+efi_status_t
+smm_variable_client::set_var_check_property(const EFI_GUID &guid, const std::u16string &name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property,
+ size_t override_name_size)
+{
+ efi_status_t efi_status = EFI_NOT_READY;
+
+ size_t name_size = string_get_size_in_bytes(name);
+ size_t req_len = SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size);
+ size_t resp_len = SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(session, &req_buf, req_len, resp_len);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *req_msg =
+ (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *)req_buf;
+
+ req_msg->Guid = guid;
+ req_msg->NameSize = name_size;
+ req_msg->VariableProperty = check_property;
+
+ memcpy(req_msg->Name, name.data(), name_size);
+
+ /* To support invalid size testing, use override if set */
+ if (override_name_size)
+ req_msg->NameSize = override_name_size;
+
+ m_err_rpc_status = rpc_caller_session_invoke(
+ call_handle, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
+ &resp_buf, &resp_len, &service_status);
+
+ if (m_err_rpc_status == RPC_SUCCESS) {
+ efi_status = service_status;
+ } else {
+ efi_status = rpc_to_efi_status();
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return efi_status;
+}
+
+efi_status_t smm_variable_client::get_var_check_property(const EFI_GUID &guid, const char16_t *name,
+ VAR_CHECK_VARIABLE_PROPERTY &check_property)
+{
+ return get_var_check_property(guid, to_variable_name(name), check_property, 0);
+}
+
+efi_status_t smm_variable_client::get_var_check_property(const EFI_GUID &guid, const char16_t *name,
+ VAR_CHECK_VARIABLE_PROPERTY &check_property,
+ size_t override_name_size)
+{
+ return get_var_check_property(guid, to_variable_name(name), check_property,
+ override_name_size);
+}
+
+efi_status_t
+smm_variable_client::get_var_check_property(const EFI_GUID &guid, const std::u16string &name,
+ VAR_CHECK_VARIABLE_PROPERTY &check_property)
+{
+ return get_var_check_property(guid, name, check_property, 0);
+}
+
+efi_status_t
+smm_variable_client::get_var_check_property(const EFI_GUID &guid, const std::u16string &name,
+ VAR_CHECK_VARIABLE_PROPERTY &check_property,
+ size_t override_name_size)
+{
+ efi_status_t efi_status = EFI_NOT_READY;
+
+ size_t name_size = string_get_size_in_bytes(name);
+ size_t req_len = SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size);
+ size_t resp_len = SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size);
+
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(session, &req_buf, req_len, resp_len);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *req_msg =
+ (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *)req_buf;
+
+ req_msg->Guid = guid;
+ req_msg->NameSize = name_size;
+
+ memcpy(req_msg->Name, name.data(), name_size);
+
+ /* To support invalid size testing, use overrides if set */
+ if (override_name_size)
+ req_msg->NameSize = override_name_size;
+
+ m_err_rpc_status = rpc_caller_session_invoke(
+ call_handle, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
+ &resp_buf, &resp_len, &service_status);
+
+ if (m_err_rpc_status == RPC_SUCCESS) {
+ efi_status = service_status;
+
+ if (efi_status == EFI_SUCCESS) {
+ efi_status = EFI_PROTOCOL_ERROR;
+
+ if (resp_len >=
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_NAME_OFFSET) {
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *resp_msg =
+ (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
+ *)resp_buf;
+
+ if (resp_len >=
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_TOTAL_SIZE(
+ resp_msg)) {
+ check_property = resp_msg->VariableProperty;
+ efi_status = EFI_SUCCESS;
+ }
+ }
+ }
+ } else {
+ efi_status = rpc_to_efi_status();
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return efi_status;
+}
+
+efi_status_t smm_variable_client::get_payload_size(size_t &payload_size)
+{
+ efi_status_t efi_status = EFI_NOT_READY;
+
+ size_t req_len = 0;
+ size_t resp_len = sizeof(SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+ rpc_call_handle call_handle;
+ uint8_t *req_buf;
+
+ call_handle = rpc_caller_session_begin(session, &req_buf, req_len, resp_len);
+
+ if (call_handle) {
+ uint8_t *resp_buf;
+ size_t resp_len;
+ service_status_t service_status;
+
+ m_err_rpc_status = rpc_caller_session_invoke(call_handle,
+ SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE,
+ &resp_buf, &resp_len, &service_status);
+
+ if (m_err_rpc_status == RPC_SUCCESS) {
+ efi_status = service_status;
+
+ if (efi_status == EFI_SUCCESS) {
+ if (resp_len >= sizeof(SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {
+ SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *resp_msg =
+ (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *)
+ resp_buf;
+
+ payload_size = resp_msg->VariablePayloadSize;
+ } else {
+ efi_status = EFI_PROTOCOL_ERROR;
+ }
+ }
+ } else {
+ efi_status = rpc_to_efi_status();
+ }
+
+ rpc_caller_session_end(call_handle);
+ }
+
+ return efi_status;
+}
+
+efi_status_t smm_variable_client::rpc_to_efi_status() const
+{
+ efi_status_t efi_status = EFI_INVALID_PARAMETER;
+
+ switch (m_err_rpc_status) {
+ case RPC_ERROR_INTERNAL:
+ efi_status = EFI_DEVICE_ERROR;
+ break;
+ case RPC_ERROR_INVALID_VALUE:
+ efi_status = EFI_INVALID_PARAMETER;
+ break;
+ case RPC_ERROR_NOT_FOUND:
+ efi_status = EFI_UNSUPPORTED;
+ break;
+ case RPC_ERROR_INVALID_STATE:
+ efi_status = EFI_NOT_READY;
+ break;
+ case RPC_ERROR_TRANSPORT_LAYER:
+ efi_status = EFI_PROTOCOL_ERROR;
+ break;
+ case RPC_ERROR_INVALID_REQUEST_BODY:
+ efi_status = EFI_PROTOCOL_ERROR;
+ break;
+ case RPC_ERROR_INVALID_RESPONSE_BODY:
+ efi_status = EFI_DEVICE_ERROR;
+ break;
+ case RPC_ERROR_RESOURCE_FAILURE:
+ efi_status = EFI_OUT_OF_RESOURCES;
+ break;
+ default:
+ break;
+ }
+
+ return efi_status;
+}
+
+void smm_variable_client::from_variable_name(const int16_t *var_name,
+ size_t name_size, std::u16string &result)
+{
+ size_t num_chars = name_size / sizeof(int16_t);
+ result.assign((const char16_t *) var_name, num_chars);
+}
diff --git a/components/service/uefi/smm_variable/client/cpp/smm_variable_client.h b/components/service/uefi/smm_variable/client/cpp/smm_variable_client.h
new file mode 100644
index 000000000..5f38ae1b4
--- /dev/null
+++ b/components/service/uefi/smm_variable/client/cpp/smm_variable_client.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMM_VARIABLE_CLIENT_H
+#define SMM_VARIABLE_CLIENT_H
+
+#include <cstdint>
+#include <protocols/common/efi/efi_status.h>
+#include <protocols/service/smm_variable/smm_variable_proto.h>
+#include <string>
+#include <vector>
+#include <uchar.h>
+
+#include "components/rpc/common/caller/rpc_caller_session.h"
+
+/*
+ * Provides a C++ client interface for accessing an instance of the smm-variable service.
+ * This client is intended for testing the UEFI variable store provided by the smm-variable
+ * service.
+ */
+class smm_variable_client {
+public:
+ smm_variable_client();
+ smm_variable_client(struct rpc_caller_session *session);
+ ~smm_variable_client();
+
+ void set_caller_session(struct rpc_caller_session *session);
+ int err_rpc_status() const;
+
+ /* Set variable with C string name. */
+ efi_status_t set_variable(const EFI_GUID &guid, const char16_t *name,
+ const std::string data, uint32_t attributes);
+
+ efi_status_t set_variable(const EFI_GUID &guid, const char16_t *name,
+ const unsigned char* data, size_t data_length,
+ uint32_t attributes);
+
+ /* Set character array variable */
+ efi_status_t set_variable(const EFI_GUID &guid, const std::u16string &name,
+ const unsigned char *data, size_t data_length,
+ uint32_t attributes);
+
+ /* Set a string type variable */
+ efi_status_t set_variable(const EFI_GUID &guid, const std::u16string &name,
+ const std::string &data, uint32_t attributes);
+
+ efi_status_t set_variable(const EFI_GUID &guid, const std::u16string &name,
+ const std::string &data, uint32_t attributes,
+ size_t override_name_size, size_t override_data_size);
+
+ /* Get a string type variable */
+ efi_status_t get_variable(const EFI_GUID &guid, const char16_t *name, std::string &data);
+ efi_status_t get_variable(const EFI_GUID &guid, const char16_t *name, std::string &data,
+ size_t override_name_size, size_t max_data_size);
+
+ efi_status_t get_variable(const EFI_GUID &guid, const std::u16string &name,
+ std::string &data);
+
+ efi_status_t get_variable(const EFI_GUID &guid, const std::u16string &name, std::string &data,
+ size_t override_name_size,
+ size_t max_data_size = MAX_VAR_DATA_SIZE);
+
+ /* Remove a variable */
+ efi_status_t remove_variable(const EFI_GUID &guid, const char16_t *name);
+ efi_status_t remove_variable(const EFI_GUID &guid, const std::u16string &name);
+
+ /* Query variable info */
+ efi_status_t query_variable_info(uint32_t attributes, size_t *max_variable_storage_size,
+ size_t *remaining_variable_storage_size,
+ size_t *max_variable_size);
+
+ /* Get the next variable name - for enumerating store contents */
+ efi_status_t get_next_variable_name(EFI_GUID &guid, std::u16string &name);
+
+ efi_status_t get_next_variable_name(EFI_GUID &guid, std::u16string &name,
+ size_t override_name_size);
+
+ /* Exit boot service */
+ efi_status_t exit_boot_service();
+
+ /* Set variable check properties */
+ efi_status_t set_var_check_property(const EFI_GUID &guid, const char16_t *name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property);
+
+ efi_status_t set_var_check_property(const EFI_GUID &guid, const char16_t *name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property,
+ size_t override_name_size);
+
+ efi_status_t set_var_check_property(const EFI_GUID &guid, const std::u16string &name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property);
+
+ efi_status_t set_var_check_property(const EFI_GUID &guid, const std::u16string &name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property,
+ size_t override_name_size);
+
+ /* Get variable check properties */
+ efi_status_t get_var_check_property(const EFI_GUID &guid, const char16_t *name,
+ VAR_CHECK_VARIABLE_PROPERTY &check_property);
+
+ efi_status_t get_var_check_property(const EFI_GUID &guid, const char16_t *name,
+ VAR_CHECK_VARIABLE_PROPERTY &check_property,
+ size_t override_name_size);
+
+ efi_status_t get_var_check_property(const EFI_GUID &guid, const std::u16string &name,
+ VAR_CHECK_VARIABLE_PROPERTY &check_property);
+
+ efi_status_t get_var_check_property(const EFI_GUID &guid, const std::u16string &name,
+ VAR_CHECK_VARIABLE_PROPERTY &check_property,
+ size_t override_name_size);
+
+ /* Get maximum variable payload size */
+ efi_status_t get_payload_size(size_t &payload_size);
+
+private:
+ /* Datasize limit set by UEFI specification */
+ static const size_t MAX_VAR_DATA_SIZE = 65536;
+
+ efi_status_t rpc_to_efi_status() const;
+
+ std::u16string to_variable_name(const char16_t *name) const;
+ void from_variable_name(const int16_t *name, size_t name_size, std::u16string &result);
+
+ struct rpc_caller_session *session;
+ int m_err_rpc_status;
+};
+
+#endif /* SMM_VARIABLE_CLIENT_H */
diff --git a/components/service/smm_variable/frontend/mm_communicate/component.cmake b/components/service/uefi/smm_variable/frontend/mm_communicate/component.cmake
index 44c1042ee..44c1042ee 100644
--- a/components/service/smm_variable/frontend/mm_communicate/component.cmake
+++ b/components/service/uefi/smm_variable/frontend/mm_communicate/component.cmake
diff --git a/components/service/smm_variable/frontend/mm_communicate/smm_variable_mm_service.c b/components/service/uefi/smm_variable/frontend/mm_communicate/smm_variable_mm_service.c
index 585fbde10..b9010e293 100644
--- a/components/service/smm_variable/frontend/mm_communicate/smm_variable_mm_service.c
+++ b/components/service/uefi/smm_variable/frontend/mm_communicate/smm_variable_mm_service.c
@@ -1,55 +1,45 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*/
-#include "protocols/common/mm/mm_smc.h"
-#include "protocols/service/smm_variable/smm_variable_proto.h"
#include "smm_variable_mm_service.h"
+
#include <assert.h>
+#include "protocols/common/mm/mm_smc.h"
+#include "protocols/service/smm_variable/smm_variable_proto.h"
+
struct smm_variable_rpc_context {
struct rpc_interface *smm_variable_rpc_interface;
};
-static rpc_opstatus_t convert_rpc_status(rpc_status_t rpc_status)
+static service_status_t convert_rpc_status(rpc_status_t rpc_status)
{
switch (rpc_status) {
- case TS_RPC_CALL_ACCEPTED:
+ case RPC_SUCCESS:
return MM_RETURN_CODE_SUCCESS;
- case TS_RPC_ERROR_EP_DOES_NOT_EXIT:
- return MM_RETURN_CODE_NOT_SUPPORTED;
-
- case TS_RPC_ERROR_INVALID_OPCODE:
- return MM_RETURN_CODE_INVALID_PARAMETER;
-
- case TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED:
- return MM_RETURN_CODE_INVALID_PARAMETER;
-
- case TS_RPC_ERROR_INVALID_REQ_BODY:
+ case RPC_ERROR_INTERNAL:
return MM_RETURN_CODE_INVALID_PARAMETER;
- case TS_RPC_ERROR_INVALID_RESP_BODY:
+ case RPC_ERROR_INVALID_VALUE:
return MM_RETURN_CODE_INVALID_PARAMETER;
- case TS_RPC_ERROR_RESOURCE_FAILURE:
- return MM_RETURN_CODE_NOT_SUPPORTED;
-
- case TS_RPC_ERROR_NOT_READY:
+ case RPC_ERROR_NOT_FOUND:
return MM_RETURN_CODE_NOT_SUPPORTED;
- case TS_RPC_ERROR_INVALID_TRANSACTION:
+ case RPC_ERROR_INVALID_STATE:
return MM_RETURN_CODE_INVALID_PARAMETER;
- case TS_RPC_ERROR_INTERNAL:
- return MM_RETURN_CODE_NOT_SUPPORTED;
+ case RPC_ERROR_TRANSPORT_LAYER:
+ return MM_RETURN_CODE_INVALID_PARAMETER;
- case TS_RPC_ERROR_INVALID_PARAMETER:
+ case RPC_ERROR_INVALID_REQUEST_BODY:
return MM_RETURN_CODE_INVALID_PARAMETER;
- case TS_RPC_ERROR_INTERFACE_DOES_NOT_EXIST:
- return MM_RETURN_CODE_NOT_SUPPORTED;
+ case RPC_ERROR_INVALID_RESPONSE_BODY:
+ return MM_RETURN_CODE_INVALID_PARAMETER;
default:
return MM_RETURN_CODE_NOT_SUPPORTED;
@@ -61,39 +51,40 @@ static int32_t smm_var_receive(struct mm_service_interface *iface,
{
SMM_VARIABLE_COMMUNICATE_HEADER *header = NULL;
struct smm_variable_mm_service *service = iface->context;
- struct call_req rpc_req = { 0 };
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ struct rpc_request rpc_req = { 0 };
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
- if (mm_req->req_buf.data_len < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)
+ if (mm_req->req_buf.data_length < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)
return MM_RETURN_CODE_DENIED;
header = (SMM_VARIABLE_COMMUNICATE_HEADER *)mm_req->req_buf.data;
rpc_req.opcode = header->Function;
- rpc_req.req_buf.data = header->Data;
- rpc_req.req_buf.data_len = mm_req->req_buf.data_len - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.req_buf.size = mm_req->req_buf.size - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.request.data = header->Data;
+ rpc_req.request.data_length =
+ mm_req->req_buf.data_length - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.request.size = mm_req->req_buf.size - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.data = header->Data;
- rpc_req.resp_buf.data_len = 0;
- rpc_req.resp_buf.size = mm_req->resp_buf.size - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.data = header->Data;
+ rpc_req.response.data_length = 0;
+ rpc_req.response.size = mm_req->resp_buf.size - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
rpc_status = service->iface->receive(service->iface, &rpc_req);
- header->ReturnStatus = rpc_req.opstatus;
+ header->ReturnStatus = rpc_req.service_status;
- if (ADD_OVERFLOW(rpc_req.resp_buf.data_len, SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
- &mm_req->resp_buf.data_len))
+ if (ADD_OVERFLOW(rpc_req.response.data_length, SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
+ &mm_req->resp_buf.data_length))
return MM_RETURN_CODE_NO_MEMORY;
- if (mm_req->resp_buf.data_len > mm_req->resp_buf.size)
+ if (mm_req->resp_buf.data_length > mm_req->resp_buf.size)
return MM_RETURN_CODE_NO_MEMORY;
return convert_rpc_status(rpc_status);
}
struct mm_service_interface *smm_variable_mm_service_init(struct smm_variable_mm_service *service,
- struct rpc_interface *iface)
+ struct rpc_service_interface *iface)
{
assert(service != NULL);
assert(iface != NULL);
diff --git a/components/service/smm_variable/frontend/mm_communicate/smm_variable_mm_service.h b/components/service/uefi/smm_variable/frontend/mm_communicate/smm_variable_mm_service.h
index 420419ff2..f1f2cc59b 100644
--- a/components/service/smm_variable/frontend/mm_communicate/smm_variable_mm_service.h
+++ b/components/service/uefi/smm_variable/frontend/mm_communicate/smm_variable_mm_service.h
@@ -6,7 +6,7 @@
#ifndef SMM_VARIABLE_MM_SERVICE_H_
#define SMM_VARIABLE_MM_SERVICE_H_
-#include "components/rpc/common/endpoint/rpc_interface.h"
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#include "components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h"
#include "protocols/service/smm_variable/smm_variable_proto.h"
@@ -20,11 +20,11 @@ extern "C" {
*/
struct smm_variable_mm_service {
struct mm_service_interface mm_service;
- struct rpc_interface *iface;
+ struct rpc_service_interface *iface;
};
struct mm_service_interface *smm_variable_mm_service_init(struct smm_variable_mm_service *service,
- struct rpc_interface *iface);
+ struct rpc_service_interface *iface);
#ifdef __cplusplus
}
diff --git a/components/service/smm_variable/frontend/mm_communicate/test/test_smm_variable_mm_service.cpp b/components/service/uefi/smm_variable/frontend/mm_communicate/test/test_smm_variable_mm_service.cpp
index 19730339c..b7114e103 100644
--- a/components/service/smm_variable/frontend/mm_communicate/test/test_smm_variable_mm_service.cpp
+++ b/components/service/uefi/smm_variable/frontend/mm_communicate/test/test_smm_variable_mm_service.cpp
@@ -1,17 +1,18 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*/
#include <CppUTest/TestHarness.h>
#include <CppUTestExt/MockSupport.h>
-#include <string.h>
#include <limits>
-#include "mock_assert.h"
+#include <string.h>
+
+#include "../smm_variable_mm_service.h"
#include "components/rpc/common/test/mock_rpc_interface.h"
+#include "mock_assert.h"
#include "protocols/common/mm/mm_smc.h"
#include "protocols/service/smm_variable/smm_variable_proto.h"
-#include "../smm_variable_mm_service.h"
TEST_GROUP(smm_variable_mm_service)
{
@@ -33,8 +34,8 @@ TEST_GROUP(smm_variable_mm_service)
}
struct smm_variable_mm_service service = { 0 };
- struct rpc_interface rpc_iface = { 0 };
- struct call_req rpc_req = { 0 };
+ struct rpc_service_interface rpc_iface = { 0 };
+ struct rpc_request rpc_req = { 0 };
struct mm_service_call_req mm_req = { 0 };
};
@@ -75,7 +76,7 @@ TEST(smm_variable_mm_service, receive_too_small)
mm_service = smm_variable_mm_service_init(&service, &rpc_iface);
- mm_req.req_buf.data_len = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE - 1;
+ mm_req.req_buf.data_length = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE - 1;
result = mm_service->receive(mm_service, &mm_req);
LONGS_EQUAL(MM_RETURN_CODE_DENIED, result);
}
@@ -84,220 +85,223 @@ TEST(smm_variable_mm_service, receive_zero_data)
{
struct mm_service_interface *mm_service = NULL;
uint8_t buffer[128] = { 0 };
- SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *) buffer;
+ SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *)buffer;
int32_t result = 0;
mm_req.req_buf.size = sizeof(buffer);
- mm_req.req_buf.data_len = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ mm_req.req_buf.data_length = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
mm_req.req_buf.data = buffer;
mm_req.resp_buf.size = sizeof(buffer);
- mm_req.resp_buf.data_len = 0;
+ mm_req.resp_buf.data_length = 0;
mm_req.resp_buf.data = buffer;
header->Function = 0x0123456789abcdefULL;
header->ReturnStatus = 0;
rpc_req.opcode = header->Function;
- rpc_req.opstatus = 0xfedcba9876543210ULL;
- rpc_req.req_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.req_buf.data_len = 0;
- rpc_req.req_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.data_len = 16;
- rpc_req.resp_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.service_status = 0xfedcba9876543210ULL;
+ rpc_req.request.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.request.data_length = 0;
+ rpc_req.request.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.data_length = 16;
+ rpc_req.response.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
rpc_iface.receive = mock_rpc_interface_receive;
mm_service = smm_variable_mm_service_init(&service, &rpc_iface);
- expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, TS_RPC_CALL_ACCEPTED);
+ expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, RPC_SUCCESS);
result = mm_service->receive(mm_service, &mm_req);
LONGS_EQUAL(MM_RETURN_CODE_SUCCESS, result);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.opstatus, header->ReturnStatus);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.resp_buf.data_len + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
- mm_req.resp_buf.data_len);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.service_status, header->ReturnStatus);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.response.data_length +
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
+ mm_req.resp_buf.data_length);
}
TEST(smm_variable_mm_service, receive_data)
{
struct mm_service_interface *mm_service = NULL;
uint8_t buffer[128] = { 0 };
- SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *) buffer;
+ SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *)buffer;
int32_t result = 0;
mm_req.req_buf.size = sizeof(buffer);
- mm_req.req_buf.data_len = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 32;
+ mm_req.req_buf.data_length = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 32;
mm_req.req_buf.data = buffer;
mm_req.resp_buf.size = sizeof(buffer);
- mm_req.resp_buf.data_len = 0;
+ mm_req.resp_buf.data_length = 0;
mm_req.resp_buf.data = buffer;
header->Function = 0x0123456789abcdefULL;
header->ReturnStatus = 0;
rpc_req.opcode = header->Function;
- rpc_req.opstatus = 0xfedcba9876543210ULL;
- rpc_req.req_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.req_buf.data_len = 32;
- rpc_req.req_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.data_len = 16;
- rpc_req.resp_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.service_status = 0xfedcba9876543210ULL;
+ rpc_req.request.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.request.data_length = 32;
+ rpc_req.request.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.data_length = 16;
+ rpc_req.response.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
rpc_iface.receive = mock_rpc_interface_receive;
mm_service = smm_variable_mm_service_init(&service, &rpc_iface);
- expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, TS_RPC_CALL_ACCEPTED);
+ expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, RPC_SUCCESS);
result = mm_service->receive(mm_service, &mm_req);
LONGS_EQUAL(MM_RETURN_CODE_SUCCESS, result);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.opstatus, header->ReturnStatus);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.resp_buf.data_len + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
- mm_req.resp_buf.data_len);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.service_status, header->ReturnStatus);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.response.data_length +
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
+ mm_req.resp_buf.data_length);
}
TEST(smm_variable_mm_service, receive_long_response)
{
struct mm_service_interface *mm_service = NULL;
uint8_t buffer[128] = { 0 };
- SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *) buffer;
+ SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *)buffer;
int32_t result = 0;
mm_req.req_buf.size = sizeof(buffer);
- mm_req.req_buf.data_len = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 32;
+ mm_req.req_buf.data_length = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 32;
mm_req.req_buf.data = buffer;
mm_req.resp_buf.size = sizeof(buffer);
- mm_req.resp_buf.data_len = 0;
+ mm_req.resp_buf.data_length = 0;
mm_req.resp_buf.data = buffer;
header->Function = 0x0123456789abcdefULL;
header->ReturnStatus = 0;
rpc_req.opcode = header->Function;
- rpc_req.opstatus = 0xfedcba9876543210ULL;
- rpc_req.req_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.req_buf.data_len = 32;
- rpc_req.req_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.data_len = std::numeric_limits<size_t>::max() - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 1;
- rpc_req.resp_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.service_status = 0xfedcba9876543210ULL;
+ rpc_req.request.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.request.data_length = 32;
+ rpc_req.request.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.data_length =
+ std::numeric_limits<size_t>::max() - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 1;
+ rpc_req.response.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
rpc_iface.receive = mock_rpc_interface_receive;
mm_service = smm_variable_mm_service_init(&service, &rpc_iface);
- expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, TS_RPC_CALL_ACCEPTED);
+ expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, RPC_SUCCESS);
result = mm_service->receive(mm_service, &mm_req);
LONGS_EQUAL(MM_RETURN_CODE_NO_MEMORY, result);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.opstatus, header->ReturnStatus);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.resp_buf.data_len + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
- mm_req.resp_buf.data_len);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.service_status, header->ReturnStatus);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.response.data_length +
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
+ mm_req.resp_buf.data_length);
}
TEST(smm_variable_mm_service, receive_response_larger_than_size)
{
struct mm_service_interface *mm_service = NULL;
uint8_t buffer[128] = { 0 };
- SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *) buffer;
+ SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *)buffer;
int32_t result = 0;
mm_req.req_buf.size = sizeof(buffer);
- mm_req.req_buf.data_len = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 32;
+ mm_req.req_buf.data_length = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 32;
mm_req.req_buf.data = buffer;
mm_req.resp_buf.size = 15 + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- mm_req.resp_buf.data_len = 0;
+ mm_req.resp_buf.data_length = 0;
mm_req.resp_buf.data = buffer;
header->Function = 0x0123456789abcdefULL;
header->ReturnStatus = 0;
rpc_req.opcode = header->Function;
- rpc_req.opstatus = 0xfedcba9876543210ULL;
- rpc_req.req_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.req_buf.data_len = 32;
- rpc_req.req_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.size = 15;
- rpc_req.resp_buf.data_len = 16;
- rpc_req.resp_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.service_status = 0xfedcba9876543210ULL;
+ rpc_req.request.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.request.data_length = 32;
+ rpc_req.request.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.size = 15;
+ rpc_req.response.data_length = 16;
+ rpc_req.response.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
rpc_iface.receive = mock_rpc_interface_receive;
mm_service = smm_variable_mm_service_init(&service, &rpc_iface);
- expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, TS_RPC_CALL_ACCEPTED);
+ expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, RPC_SUCCESS);
result = mm_service->receive(mm_service, &mm_req);
LONGS_EQUAL(MM_RETURN_CODE_NO_MEMORY, result);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.opstatus, header->ReturnStatus);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.resp_buf.data_len + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
- mm_req.resp_buf.data_len);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.service_status, header->ReturnStatus);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.response.data_length +
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
+ mm_req.resp_buf.data_length);
}
TEST(smm_variable_mm_service, receive_data_error_codes)
{
struct mm_service_interface *mm_service = NULL;
uint8_t buffer[128] = { 0 };
- SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *) buffer;
+ SMM_VARIABLE_COMMUNICATE_HEADER *header = (SMM_VARIABLE_COMMUNICATE_HEADER *)buffer;
int32_t result = 0;
const struct {
rpc_status_t rpc_status;
int32_t mm_result;
} status_mapping[] = {
- {TS_RPC_CALL_ACCEPTED, MM_RETURN_CODE_SUCCESS},
- {TS_RPC_ERROR_EP_DOES_NOT_EXIT, MM_RETURN_CODE_NOT_SUPPORTED},
- {TS_RPC_ERROR_INVALID_OPCODE, MM_RETURN_CODE_INVALID_PARAMETER},
- {TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED, MM_RETURN_CODE_INVALID_PARAMETER},
- {TS_RPC_ERROR_INVALID_REQ_BODY, MM_RETURN_CODE_INVALID_PARAMETER},
- {TS_RPC_ERROR_INVALID_RESP_BODY, MM_RETURN_CODE_INVALID_PARAMETER},
- {TS_RPC_ERROR_RESOURCE_FAILURE, MM_RETURN_CODE_NOT_SUPPORTED},
- {TS_RPC_ERROR_NOT_READY, MM_RETURN_CODE_NOT_SUPPORTED},
- {TS_RPC_ERROR_INVALID_TRANSACTION, MM_RETURN_CODE_INVALID_PARAMETER},
- {TS_RPC_ERROR_INTERNAL, MM_RETURN_CODE_NOT_SUPPORTED},
- {TS_RPC_ERROR_INVALID_PARAMETER, MM_RETURN_CODE_INVALID_PARAMETER},
- {TS_RPC_ERROR_INTERFACE_DOES_NOT_EXIST, MM_RETURN_CODE_NOT_SUPPORTED},
- {1, MM_RETURN_CODE_NOT_SUPPORTED}
+ { RPC_SUCCESS, MM_RETURN_CODE_SUCCESS },
+ { RPC_ERROR_INTERNAL, MM_RETURN_CODE_INVALID_PARAMETER },
+ { RPC_ERROR_INVALID_VALUE, MM_RETURN_CODE_INVALID_PARAMETER },
+ { RPC_ERROR_NOT_FOUND, MM_RETURN_CODE_NOT_SUPPORTED },
+ { RPC_ERROR_INVALID_STATE, MM_RETURN_CODE_INVALID_PARAMETER },
+ { RPC_ERROR_TRANSPORT_LAYER, MM_RETURN_CODE_INVALID_PARAMETER },
+ { RPC_ERROR_INVALID_REQUEST_BODY, MM_RETURN_CODE_INVALID_PARAMETER },
+ { RPC_ERROR_INVALID_RESPONSE_BODY, MM_RETURN_CODE_INVALID_PARAMETER },
+ { 1, MM_RETURN_CODE_NOT_SUPPORTED }
};
mm_req.req_buf.size = sizeof(buffer);
- mm_req.req_buf.data_len = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 32;
+ mm_req.req_buf.data_length = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + 32;
mm_req.req_buf.data = buffer;
mm_req.resp_buf.size = sizeof(buffer);
- mm_req.resp_buf.data_len = 0;
+ mm_req.resp_buf.data_length = 0;
mm_req.resp_buf.data = buffer;
header->Function = 0x0123456789abcdefULL;
header->ReturnStatus = 0;
rpc_req.opcode = header->Function;
- rpc_req.opstatus = 0xfedcba9876543210ULL;
- rpc_req.req_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.req_buf.data_len = 32;
- rpc_req.req_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- rpc_req.resp_buf.data_len = 16;
- rpc_req.resp_buf.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.service_status = 0xfedcba9876543210ULL;
+ rpc_req.request.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.request.data_length = 32;
+ rpc_req.request.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.size = sizeof(buffer) - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ rpc_req.response.data_length = 16;
+ rpc_req.response.data = buffer + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
rpc_iface.receive = mock_rpc_interface_receive;
mm_service = smm_variable_mm_service_init(&service, &rpc_iface);
for (size_t i = 0; i < ARRAY_SIZE(status_mapping); i++) {
- expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req, status_mapping[i].rpc_status);
+ expect_mock_rpc_interface_receive(&rpc_iface, &rpc_req,
+ status_mapping[i].rpc_status);
result = mm_service->receive(mm_service, &mm_req);
LONGS_EQUAL(status_mapping[i].mm_result, result);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.opstatus, header->ReturnStatus);
- UNSIGNED_LONGLONGS_EQUAL(rpc_req.resp_buf.data_len + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
- mm_req.resp_buf.data_len);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.service_status, header->ReturnStatus);
+ UNSIGNED_LONGLONGS_EQUAL(rpc_req.response.data_length +
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE,
+ mm_req.resp_buf.data_length);
}
}
diff --git a/components/service/smm_variable/frontend/mm_communicate/tests.cmake b/components/service/uefi/smm_variable/frontend/mm_communicate/tests.cmake
index d1f930c99..50b0b9ac8 100644
--- a/components/service/smm_variable/frontend/mm_communicate/tests.cmake
+++ b/components/service/uefi/smm_variable/frontend/mm_communicate/tests.cmake
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2021, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -12,13 +12,13 @@ unit_test_add_suite(
${CMAKE_CURRENT_LIST_DIR}/smm_variable_mm_service.c
${CMAKE_CURRENT_LIST_DIR}/test/test_smm_variable_mm_service.cpp
${UNIT_TEST_PROJECT_PATH}/components/rpc/common/test/mock_rpc_interface.cpp
- ${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/test/mock_assert.cpp
+ ${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/mock/mock_assert.cpp
INCLUDE_DIRECTORIES
${UNIT_TEST_PROJECT_PATH}
${UNIT_TEST_PROJECT_PATH}/components/rpc/mm_communicate/endpoint/sp
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/include
- ${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/test
+ ${UNIT_TEST_PROJECT_PATH}/components/messaging/ffa/libsp/mock
${UNIT_TEST_PROJECT_PATH}/components/rpc/common/interface
COMPILE_DEFINITIONS
-DARM64
diff --git a/components/service/smm_variable/provider/component.cmake b/components/service/uefi/smm_variable/provider/component.cmake
index f20d18ffc..f20d18ffc 100644
--- a/components/service/smm_variable/provider/component.cmake
+++ b/components/service/uefi/smm_variable/provider/component.cmake
diff --git a/components/service/uefi/smm_variable/provider/smm_variable_provider.c b/components/service/uefi/smm_variable/provider/smm_variable_provider.c
new file mode 100644
index 000000000..18753975a
--- /dev/null
+++ b/components/service/uefi/smm_variable/provider/smm_variable_provider.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "smm_variable_provider.h"
+
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/smm_variable/smm_variable_proto.h>
+#include <stddef.h>
+#include <string.h>
+
+/* Service request handlers */
+static rpc_status_t get_variable_handler(void *context, struct rpc_request *req);
+static rpc_status_t get_next_variable_name_handler(void *context, struct rpc_request *req);
+static rpc_status_t set_variable_handler(void *context, struct rpc_request *req);
+static rpc_status_t query_variable_info_handler(void *context, struct rpc_request *req);
+static rpc_status_t exit_boot_service_handler(void *context, struct rpc_request *req);
+static rpc_status_t set_var_check_property_handler(void *context, struct rpc_request *req);
+static rpc_status_t get_var_check_property_handler(void *context, struct rpc_request *req);
+static rpc_status_t get_payload_size_handler(void *context, struct rpc_request *req);
+
+/* Handler mapping table for service */
+static const struct service_handler handler_table[] = {
+ { SMM_VARIABLE_FUNCTION_GET_VARIABLE, get_variable_handler },
+ { SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, get_next_variable_name_handler },
+ { SMM_VARIABLE_FUNCTION_SET_VARIABLE, set_variable_handler },
+ { SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, query_variable_info_handler },
+ { SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, exit_boot_service_handler },
+ { SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET, set_var_check_property_handler },
+ { SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, get_var_check_property_handler },
+ { SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, get_payload_size_handler }
+};
+
+struct rpc_service_interface *smm_variable_provider_init(struct smm_variable_provider *context,
+ uint32_t owner_id, size_t max_variables,
+ struct storage_backend *persistent_store,
+ struct storage_backend *volatile_store)
+{
+ struct rpc_service_interface *rpc_interface = NULL;
+ const struct rpc_uuid dummy_uuid = { .uuid = { 0 } };
+
+ if (context) {
+ service_provider_init(&context->base_provider, context, &dummy_uuid, handler_table,
+ sizeof(handler_table) / sizeof(struct service_handler));
+
+ if (uefi_variable_store_init(&context->variable_store, owner_id, max_variables,
+ persistent_store, volatile_store) == EFI_SUCCESS) {
+ rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+ }
+ }
+
+ return rpc_interface;
+}
+
+void smm_variable_provider_deinit(struct smm_variable_provider *context)
+{
+ uefi_variable_store_deinit(&context->variable_store);
+}
+
+static efi_status_t sanitize_access_variable_param(struct rpc_request *req, size_t *param_len)
+{
+ efi_status_t efi_status = EFI_INVALID_PARAMETER;
+ *param_len = 0;
+ const struct rpc_buffer *req_buf = &req->request;
+
+ if (req_buf->data_length >= SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET) {
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *param =
+ (const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)req_buf->data;
+
+ size_t max_space_for_name =
+ req_buf->data_length - SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
+
+ if (param->NameSize <= max_space_for_name) {
+ *param_len = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(param);
+ efi_status = EFI_SUCCESS;
+ }
+ }
+
+ return efi_status;
+}
+
+static efi_status_t sanitize_get_next_var_name_param(struct rpc_request *req, size_t *param_len)
+{
+ efi_status_t efi_status = EFI_INVALID_PARAMETER;
+ *param_len = 0;
+ const struct rpc_buffer *req_buf = &req->request;
+
+ if (req_buf->data_length >= SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET) {
+ const SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *param =
+ (const SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *)req_buf->data;
+
+ size_t max_space_for_name =
+ req_buf->data_length -
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET;
+
+ if (param->NameSize <= max_space_for_name) {
+ *param_len =
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_TOTAL_SIZE(param);
+ efi_status = EFI_SUCCESS;
+ }
+ }
+
+ return efi_status;
+}
+
+static efi_status_t sanitize_var_check_property_param(struct rpc_request *req, size_t *param_len)
+{
+ efi_status_t efi_status = EFI_INVALID_PARAMETER;
+ *param_len = 0;
+ const struct rpc_buffer *req_buf = &req->request;
+
+ if (req_buf->data_length >=
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_NAME_OFFSET) {
+ const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *param =
+ (const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *)req_buf->data;
+
+ size_t max_space_for_name =
+ req_buf->data_length -
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_NAME_OFFSET;
+
+ if (param->NameSize <= max_space_for_name) {
+ *param_len =
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_TOTAL_SIZE(
+ param);
+ efi_status = EFI_SUCCESS;
+ }
+ }
+
+ return efi_status;
+}
+
+static rpc_status_t get_variable_handler(void *context, struct rpc_request *req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider *)context;
+
+ size_t param_len = 0;
+ efi_status_t efi_status = sanitize_access_variable_param(req, &param_len);
+
+ if (efi_status == EFI_SUCCESS) {
+ /* Valid access variable header parameter */
+ struct rpc_buffer *resp_buf = &req->response;
+
+ if (resp_buf->size >= param_len) {
+ struct rpc_buffer *req_buf = &req->request;
+ size_t max_data_len = resp_buf->size - param_len;
+
+ memmove(resp_buf->data, req_buf->data, param_len);
+
+ efi_status = uefi_variable_store_get_variable(
+ &this_instance->variable_store,
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)resp_buf->data,
+ max_data_len, &resp_buf->data_length);
+ } else {
+ /* Response buffer not big enough */
+ efi_status = EFI_BAD_BUFFER_SIZE;
+ }
+ }
+
+ req->service_status = efi_status;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t get_next_variable_name_handler(void *context, struct rpc_request *req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider *)context;
+
+ size_t param_len = 0;
+ efi_status_t efi_status = sanitize_get_next_var_name_param(req, &param_len);
+
+ if (efi_status == EFI_SUCCESS) {
+ /* Valid get next variable name header */
+ struct rpc_buffer *resp_buf = &req->response;
+
+ if (resp_buf->size >= param_len) {
+ struct rpc_buffer *req_buf = &req->request;
+ size_t max_name_len =
+ resp_buf->size -
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET;
+
+ memmove(resp_buf->data, req_buf->data, param_len);
+
+ efi_status = uefi_variable_store_get_next_variable_name(
+ &this_instance->variable_store,
+ (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *)resp_buf->data,
+ max_name_len, &resp_buf->data_length);
+ } else {
+ /* Reponse buffer not big enough */
+ efi_status = EFI_BAD_BUFFER_SIZE;
+ }
+ }
+
+ req->service_status = efi_status;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t set_variable_handler(void *context, struct rpc_request *req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider *)context;
+
+ size_t param_len = 0;
+ efi_status_t efi_status = sanitize_access_variable_param(req, &param_len);
+
+ if (efi_status == EFI_SUCCESS) {
+ /* Access variable header is whole. Check that buffer length can
+ * accommodate the data.
+ */
+ struct rpc_buffer *req_buf = &req->request;
+
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_var =
+ (const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)req_buf->data;
+
+ size_t space_for_data =
+ req_buf->data_length -
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_var);
+
+ if (access_var->DataSize <= space_for_data) {
+ efi_status = uefi_variable_store_set_variable(
+ &this_instance->variable_store, access_var);
+ } else {
+ /* Invalid DataSize */
+ efi_status = EFI_INVALID_PARAMETER;
+ }
+ }
+
+ req->service_status = efi_status;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t query_variable_info_handler(void *context, struct rpc_request *req)
+{
+ efi_status_t efi_status = EFI_INVALID_PARAMETER;
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider *)context;
+
+ const struct rpc_buffer *req_buf = &req->request;
+
+ if (req_buf->data_length >= sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
+ struct rpc_buffer *resp_buf = &req->response;
+
+ if (resp_buf->size >= req_buf->data_length) {
+ memmove(resp_buf->data, req_buf->data, req_buf->data_length);
+
+ efi_status = uefi_variable_store_query_variable_info(
+ &this_instance->variable_store,
+ (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *)resp_buf->data);
+
+ if (efi_status == EFI_SUCCESS) {
+ resp_buf->data_length =
+ sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
+ }
+ } else {
+ /* Reponse buffer not big enough */
+ efi_status = EFI_BAD_BUFFER_SIZE;
+ }
+ }
+
+ req->service_status = efi_status;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t exit_boot_service_handler(void *context, struct rpc_request *req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider *)context;
+
+ efi_status_t efi_status =
+ uefi_variable_store_exit_boot_service(&this_instance->variable_store);
+ req->service_status = efi_status;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t set_var_check_property_handler(void *context, struct rpc_request *req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider *)context;
+
+ size_t param_len = 0;
+ efi_status_t efi_status = sanitize_var_check_property_param(req, &param_len);
+
+ if (efi_status == EFI_SUCCESS) {
+ /* Request parameter structue looks whole */
+ struct rpc_buffer *req_buf = &req->request;
+
+ const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *check_property =
+ (const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *)req_buf->data;
+
+ efi_status = uefi_variable_store_set_var_check_property(
+ &this_instance->variable_store, check_property);
+ }
+
+ req->service_status = efi_status;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t get_var_check_property_handler(void *context, struct rpc_request *req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider *)context;
+
+ size_t param_len = 0;
+ efi_status_t efi_status = sanitize_var_check_property_param(req, &param_len);
+
+ if (efi_status == EFI_SUCCESS) {
+ /* Request parameter structue looks whole */
+ struct rpc_buffer *resp_buf = &req->response;
+
+ if (resp_buf->size >= param_len) {
+ struct rpc_buffer *req_buf = &req->request;
+ memmove(resp_buf->data, req_buf->data, param_len);
+ resp_buf->data_length = param_len;
+
+ efi_status = uefi_variable_store_get_var_check_property(
+ &this_instance->variable_store,
+ (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *)
+ resp_buf->data);
+ } else {
+ /* Reponse buffer not big enough */
+ efi_status = EFI_BAD_BUFFER_SIZE;
+ }
+ }
+
+ req->service_status = efi_status;
+
+ return RPC_SUCCESS;
+}
+
+static rpc_status_t get_payload_size_handler(void *context, struct rpc_request *req)
+{
+ (void)context;
+
+ /* Payload size is constrained by the size of the RPC call buffer. Because the variable length
+ * name is also carried in the buffer, the maximum payload size depends on the name size. This
+ * function therefore treats the payload as name + data.
+ */
+ size_t payload_size =
+ req->request.size - SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
+
+ efi_status_t efi_status = EFI_SUCCESS;
+ struct rpc_buffer *resp_buf = &req->response;
+
+ if (resp_buf->size >= sizeof(SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {
+ SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *resp_msg =
+ (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *)resp_buf->data;
+
+ resp_msg->VariablePayloadSize = payload_size;
+ resp_buf->data_length = sizeof(SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+ } else {
+ /* Reponse buffer not big enough */
+ efi_status = EFI_BAD_BUFFER_SIZE;
+ }
+
+ req->service_status = efi_status;
+
+ return RPC_SUCCESS;
+}
diff --git a/components/service/smm_variable/provider/smm_variable_provider.h b/components/service/uefi/smm_variable/provider/smm_variable_provider.h
index c6793977f..e86ad82ce 100644
--- a/components/service/smm_variable/provider/smm_variable_provider.h
+++ b/components/service/uefi/smm_variable/provider/smm_variable_provider.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,9 +7,9 @@
#ifndef SMM_VARIABLE_PROVIDER_H
#define SMM_VARIABLE_PROVIDER_H
-#include <rpc/common/endpoint/rpc_interface.h>
-#include <service/common/provider/service_provider.h>
-#include <service/smm_variable/backend/uefi_variable_store.h>
+#include "rpc/common/endpoint/rpc_service_interface.h"
+#include "service/common/provider/service_provider.h"
+#include "service/uefi/smm_variable/backend/uefi_variable_store.h"
#ifdef __cplusplus
extern "C" {
@@ -19,8 +19,7 @@ extern "C" {
* The smm_variable_provider is a service provider that implements an RPC interface
* for an instance of the smm_variable service.
*/
-struct smm_variable_provider
-{
+struct smm_variable_provider {
struct service_provider base_provider;
struct uefi_variable_store variable_store;
};
@@ -41,20 +40,17 @@ struct smm_variable_provider
*
* \return An rpc_interface or NULL on failure
*/
-struct rpc_interface *smm_variable_provider_init(
- struct smm_variable_provider *context,
- uint32_t owner_id,
- size_t max_variables,
- struct storage_backend *persistent_store,
- struct storage_backend *volatile_store);
+struct rpc_service_interface *smm_variable_provider_init(struct smm_variable_provider *context,
+ uint32_t owner_id, size_t max_variables,
+ struct storage_backend *persistent_store,
+ struct storage_backend *volatile_store);
/**
* \brief Cleans up when the instance is no longer needed
*
* \param[in] context The instance to de-initialize
*/
-void smm_variable_provider_deinit(
- struct smm_variable_provider *context);
+void smm_variable_provider_deinit(struct smm_variable_provider *context);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/KEK.h b/components/service/uefi/smm_variable/test/service/auth_vectors/KEK.h
new file mode 100644
index 000000000..9b28ed367
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/KEK.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char KEK_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0,
+ 0x7a, 0xa6, 0xe6, 0x9b, 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b,
+ 0xc7, 0xa8, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x50, 0x4b, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xcb, 0x94, 0x4f, 0x33, 0x47, 0xe3, 0xb3,
+ 0xd0, 0x34, 0x45, 0x48, 0xea, 0x6c, 0x66, 0x8d, 0xb0, 0x97, 0x41, 0xe8,
+ 0x81, 0x7f, 0xab, 0x83, 0xa5, 0x9f, 0xa6, 0x5d, 0x47, 0x9b, 0x60, 0x55,
+ 0xc3, 0x70, 0x2c, 0xf5, 0x96, 0x9f, 0xa8, 0xdb, 0xc0, 0xca, 0x63, 0x7c,
+ 0x34, 0xed, 0x14, 0x9e, 0xc0, 0xbe, 0xab, 0xe4, 0x3b, 0x73, 0xed, 0x62,
+ 0x24, 0xe8, 0x68, 0xa4, 0x14, 0x10, 0x50, 0x8f, 0x7f, 0x59, 0xad, 0xec,
+ 0x16, 0x60, 0xfe, 0x1f, 0x60, 0x3b, 0x9a, 0x7b, 0x7a, 0xc3, 0x3e, 0xf4,
+ 0xcf, 0x39, 0x27, 0x70, 0xb9, 0xd9, 0x0a, 0x40, 0xc7, 0x7f, 0x41, 0x80,
+ 0xd3, 0xe0, 0x22, 0x15, 0x1a, 0x91, 0x0e, 0x4a, 0xa7, 0x52, 0x33, 0x72,
+ 0xf2, 0x46, 0x03, 0x42, 0x36, 0x85, 0x27, 0xf0, 0x2f, 0x9f, 0x56, 0xa4,
+ 0xd5, 0xdc, 0x00, 0xd5, 0x5e, 0xe5, 0x1a, 0x08, 0xae, 0xdc, 0x80, 0xb9,
+ 0xa4, 0xcf, 0x58, 0xf1, 0xd4, 0x38, 0x5f, 0xe1, 0xff, 0x81, 0x01, 0xff,
+ 0x17, 0x77, 0xe7, 0x4b, 0xee, 0x91, 0xaf, 0x3a, 0xf9, 0x73, 0xd9, 0x6f,
+ 0xe9, 0x22, 0x55, 0x15, 0x17, 0xa9, 0xc9, 0xde, 0xfc, 0x63, 0xfc, 0x84,
+ 0x96, 0xb7, 0xf8, 0x40, 0x63, 0x5f, 0x2c, 0x21, 0x20, 0x1e, 0x37, 0x14,
+ 0x1b, 0x4e, 0x76, 0xec, 0x3a, 0xcb, 0xd5, 0xdc, 0xef, 0x96, 0x37, 0x43,
+ 0x46, 0x4c, 0x2e, 0xf4, 0xcb, 0x58, 0x90, 0x91, 0x35, 0x6d, 0xb5, 0x58,
+ 0xb8, 0xb7, 0x74, 0x72, 0x80, 0x3f, 0xb7, 0xd0, 0x1b, 0xca, 0x47, 0x18,
+ 0xc9, 0x99, 0x4d, 0x74, 0x97, 0x57, 0xc4, 0x2f, 0x2e, 0x2a, 0xd0, 0x95,
+ 0xc2, 0x1e, 0x64, 0x8d, 0xbd, 0xd1, 0x7e, 0xf6, 0x6c, 0x44, 0x01, 0x1f,
+ 0x37, 0xc0, 0x67, 0x7a, 0x78, 0x47, 0x21, 0xb4, 0x0d, 0xc6, 0xab, 0x81,
+ 0x7e, 0x1c, 0x10, 0x5d, 0x01, 0x2e, 0xfe, 0x41, 0x93, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4,
+ 0xbb, 0x06, 0xa7, 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66,
+ 0x08, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4, 0xbb, 0x06, 0xa7,
+ 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66, 0x08, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3a,
+ 0xae, 0xa0, 0xfa, 0x34, 0x4a, 0x52, 0x24, 0x90, 0x3a, 0xba, 0x33, 0x61,
+ 0x0f, 0xc8, 0x6f, 0xbc, 0x72, 0xf8, 0xc3, 0x98, 0x04, 0xe1, 0xcb, 0xf2,
+ 0x82, 0xfd, 0x83, 0x59, 0x51, 0x23, 0x71, 0xf4, 0xce, 0xe9, 0x36, 0x4d,
+ 0x0a, 0xd3, 0x11, 0x6d, 0x51, 0xb7, 0xd1, 0x9f, 0x9b, 0x85, 0x5c, 0x25,
+ 0x11, 0x9c, 0x13, 0xf6, 0x33, 0xd8, 0xa4, 0x27, 0xef, 0x90, 0x56, 0x21,
+ 0xe3, 0x90, 0x10, 0x2b, 0x50, 0x46, 0x6e, 0x8a, 0x84, 0x3e, 0x30, 0x4c,
+ 0xc2, 0xdf, 0x81, 0x60, 0xdf, 0xb8, 0x06, 0xd8, 0x2f, 0xcf, 0x3f, 0xb8,
+ 0xbe, 0x04, 0xa4, 0xbb, 0xba, 0x65, 0x9f, 0x4e, 0xc4, 0x05, 0xbe, 0x9e,
+ 0xfe, 0xa9, 0x0c, 0x06, 0x81, 0xcc, 0xa4, 0x66, 0xb0, 0x14, 0x48, 0xc9,
+ 0x24, 0x88, 0xd8, 0xdc, 0xf2, 0x5c, 0xb5, 0x59, 0x66, 0x4f, 0xc6, 0xa4,
+ 0xa3, 0x96, 0xa8, 0x48, 0x3b, 0x43, 0xff, 0xe0, 0x10, 0x53, 0x79, 0x47,
+ 0x74, 0xe8, 0xbc, 0xa9, 0x4f, 0x8e, 0x1f, 0xfb, 0xf8, 0xad, 0x8d, 0x10,
+ 0x80, 0x8f, 0x80, 0xf8, 0x5b, 0x36, 0xff, 0x60, 0x0b, 0x3f, 0xb2, 0x2f,
+ 0x46, 0x27, 0x43, 0x00, 0x1a, 0x0d, 0xb8, 0x91, 0x4e, 0x84, 0xb1, 0x94,
+ 0xc2, 0xca, 0xd6, 0x36, 0x4d, 0xc6, 0xda, 0x53, 0x71, 0xcc, 0xc8, 0x8e,
+ 0x9c, 0xdb, 0x31, 0xbb, 0x93, 0x49, 0xa7, 0xf4, 0x0b, 0x19, 0xcb, 0xaa,
+ 0x2b, 0x0c, 0xf4, 0xc7, 0x59, 0x8a, 0xc6, 0x59, 0x0b, 0x1d, 0x2f, 0xc3,
+ 0xcf, 0x06, 0xcf, 0x2e, 0x6b, 0x15, 0x6f, 0xba, 0xd1, 0xfa, 0x7d, 0x7f,
+ 0xaa, 0x99, 0x09, 0x63, 0xa8, 0xdd, 0x6c, 0xdb, 0x6a, 0x5e, 0x00, 0x5e,
+ 0x89, 0x11, 0xe3, 0xbd, 0xf6, 0xcb, 0x13, 0x89, 0x6a, 0xb8, 0x7e, 0x89,
+ 0xbc, 0xa5, 0xec, 0x68, 0x85, 0xf0, 0xaa, 0x05, 0x91, 0xc1, 0x79, 0xa1,
+ 0x1c, 0x9d, 0x32, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x31, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0, 0x7a, 0xa6, 0xe6, 0x9b,
+ 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b, 0xc7, 0xa8, 0x37, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x83, 0x75, 0x52,
+ 0xe9, 0x31, 0x81, 0x65, 0x22, 0x9d, 0x8e, 0x5f, 0xeb, 0x86, 0x0a, 0x0c,
+ 0x10, 0x1f, 0xe2, 0x2e, 0xed, 0x1a, 0x88, 0x02, 0xfc, 0xd8, 0x50, 0xaa,
+ 0xa8, 0xdd, 0x1f, 0xfd, 0x25, 0xac, 0xd8, 0x2d, 0xe1, 0x06, 0x4e, 0x1a,
+ 0xad, 0xbe, 0x00, 0xe1, 0x59, 0x23, 0x92, 0x78, 0xf2, 0x31, 0x62, 0x67,
+ 0xa6, 0x3a, 0x0a, 0x04, 0x21, 0xb2, 0xeb, 0x72, 0x99, 0xab, 0xad, 0xdb,
+ 0xee, 0x2f, 0x21, 0x6a, 0x71, 0xfe, 0x67, 0x89, 0x3d, 0xf5, 0xce, 0x4b,
+ 0x89, 0x79, 0x07, 0x3a, 0xfd, 0xc3, 0xb2, 0x39, 0x2c, 0xec, 0x4f, 0x96,
+ 0xcc, 0xc9, 0xd3, 0xd9, 0x9c, 0x92, 0x1a, 0xbe, 0x37, 0xd2, 0xc7, 0x4b,
+ 0x61, 0xbd, 0x95, 0x0a, 0x0a, 0x9b, 0xb9, 0x10, 0xce, 0x7a, 0x38, 0x28,
+ 0x92, 0xbb, 0x2c, 0xc6, 0x9d, 0xf7, 0x3b, 0xec, 0xd5, 0x3b, 0xd9, 0x1b,
+ 0xbb, 0x15, 0x09, 0x55, 0x3f, 0x38, 0x05, 0x6b, 0x3c, 0xf4, 0x9c, 0xb5,
+ 0x50, 0xf0, 0x50, 0x09, 0xf1, 0x0a, 0xd4, 0x19, 0x10, 0xb6, 0x32, 0x68,
+ 0xf0, 0x51, 0xd8, 0x18, 0x4d, 0xe3, 0x99, 0x11, 0x89, 0x42, 0x1b, 0xe5,
+ 0x89, 0x86, 0x09, 0x58, 0x69, 0x31, 0x1d, 0x06, 0xc0, 0xa4, 0x38, 0x3a,
+ 0x96, 0x71, 0xab, 0xd9, 0xe3, 0x61, 0xb9, 0x9c, 0x40, 0x4d, 0x9c, 0x20,
+ 0x25, 0x55, 0xc3, 0x52, 0xd8, 0x03, 0x17, 0xf7, 0x9f, 0x7a, 0x2b, 0xa4,
+ 0xb7, 0xa7, 0x85, 0x53, 0x2a, 0x93, 0x28, 0x23, 0xa0, 0xf3, 0x18, 0xee,
+ 0x9e, 0x38, 0x90, 0x07, 0xbb, 0x70, 0x29, 0xab, 0x35, 0x8b, 0xc5, 0x45,
+ 0x00, 0xd8, 0xd8, 0x25, 0x56, 0x41, 0xbb, 0xe2, 0x0f, 0x3b, 0xd1, 0xfb,
+ 0x36, 0xd3, 0x9c, 0x6c, 0xf1, 0x8a, 0x31, 0x20, 0x93, 0xb4, 0xa6, 0x4f,
+ 0x15, 0xe7, 0xcd, 0xfa, 0xc6, 0x2e, 0x1d, 0x2f, 0xe5, 0x91, 0x7e, 0x66,
+ 0xe5, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab,
+ 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03,
+ 0x07, 0x30, 0x82, 0x01, 0xef, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+ 0x11, 0x90, 0xbd, 0xc1, 0x8a, 0x36, 0x84, 0x80, 0x84, 0xa0, 0xe2, 0x8f,
+ 0x57, 0xc9, 0x25, 0x01, 0xd7, 0x71, 0x9f, 0x6f, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x33, 0x30, 0x1e, 0x17, 0x0d,
+ 0x32, 0x34, 0x30, 0x31, 0x32, 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38,
+ 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32,
+ 0x30, 0x30, 0x38, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+ 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd4, 0x89,
+ 0x82, 0x3f, 0x53, 0x8c, 0x94, 0xba, 0xbf, 0xff, 0xfd, 0x18, 0x9b, 0xa0,
+ 0x30, 0x7e, 0x56, 0xd7, 0xe1, 0xdb, 0x77, 0x88, 0x35, 0xa8, 0x20, 0x69,
+ 0xe2, 0x3a, 0xcf, 0x0b, 0x87, 0xd0, 0x06, 0x39, 0x83, 0x46, 0x15, 0xe8,
+ 0x36, 0xf1, 0xf5, 0x3e, 0x46, 0xed, 0xa8, 0x8c, 0x11, 0x33, 0x9f, 0x72,
+ 0xc0, 0x57, 0xd0, 0x06, 0x35, 0x06, 0xc7, 0xd5, 0xdb, 0xeb, 0x3d, 0x12,
+ 0xc4, 0xc2, 0x0c, 0x5e, 0x14, 0xf4, 0x7c, 0x3a, 0xd8, 0x55, 0x37, 0xcd,
+ 0x55, 0x2c, 0x37, 0x98, 0x2b, 0xdb, 0x3b, 0xfe, 0x70, 0x06, 0x56, 0x64,
+ 0x03, 0x64, 0x13, 0xd6, 0x73, 0xf3, 0x93, 0x8b, 0xc3, 0x37, 0xa5, 0xb7,
+ 0xa0, 0x40, 0xb6, 0x3d, 0x7e, 0x79, 0x86, 0xc6, 0x33, 0x3c, 0x2a, 0x5a,
+ 0x0f, 0x91, 0x91, 0xef, 0xdb, 0xca, 0x47, 0x58, 0x83, 0xde, 0x22, 0x81,
+ 0x8f, 0x19, 0x49, 0x6f, 0x3b, 0xae, 0x06, 0xad, 0xda, 0xb6, 0xad, 0x04,
+ 0x62, 0xe2, 0xb0, 0x14, 0xc4, 0xb0, 0xc3, 0x7d, 0x2f, 0x48, 0x19, 0x75,
+ 0xd0, 0xda, 0x81, 0x60, 0x0d, 0x03, 0xbd, 0x1b, 0xfd, 0xb6, 0x10, 0x7b,
+ 0x23, 0x4e, 0x91, 0xa6, 0xff, 0xbd, 0xd5, 0xfe, 0xd7, 0x3f, 0x63, 0x53,
+ 0x1f, 0x48, 0xe5, 0xc9, 0x6d, 0x69, 0xcd, 0x0e, 0xde, 0x54, 0xe3, 0x42,
+ 0xb6, 0xdc, 0x12, 0x2e, 0x0c, 0xcf, 0x40, 0x58, 0x52, 0xef, 0xad, 0x8d,
+ 0xf4, 0x52, 0x56, 0xda, 0x3b, 0x47, 0xb1, 0x4c, 0xc6, 0xe1, 0x3a, 0x6f,
+ 0x28, 0xe9, 0xf9, 0x10, 0x86, 0x37, 0x24, 0x74, 0xe5, 0x03, 0xb1, 0x95,
+ 0x71, 0xe4, 0xf4, 0xe5, 0xaa, 0xb3, 0x88, 0x15, 0x20, 0x3c, 0xc8, 0x00,
+ 0x2d, 0x04, 0x4a, 0x7e, 0x35, 0x7c, 0x70, 0xb1, 0xa6, 0xad, 0x82, 0xa0,
+ 0x77, 0xb5, 0x4d, 0xd4, 0x92, 0x0c, 0x9a, 0xca, 0x8b, 0xdd, 0x75, 0x28,
+ 0xae, 0x99, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30,
+ 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xae, 0xfa,
+ 0xbf, 0x66, 0xb9, 0xc6, 0xf2, 0x3b, 0x01, 0x7f, 0x52, 0x90, 0x41, 0x6d,
+ 0x0e, 0x33, 0x51, 0x01, 0x7c, 0x7e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xae, 0xfa, 0xbf, 0x66, 0xb9,
+ 0xc6, 0xf2, 0x3b, 0x01, 0x7f, 0x52, 0x90, 0x41, 0x6d, 0x0e, 0x33, 0x51,
+ 0x01, 0x7c, 0x7e, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+ 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x01, 0x00, 0xb8, 0xdb, 0x9a, 0x38, 0x6e, 0xb1, 0x48, 0xe0,
+ 0x5a, 0x9b, 0xd5, 0xec, 0x2e, 0xe5, 0x8a, 0xb5, 0xc7, 0x4e, 0x9f, 0xe9,
+ 0x8d, 0xde, 0x11, 0xc5, 0xe0, 0x8a, 0x75, 0xe6, 0x04, 0x7e, 0xfa, 0xcb,
+ 0x3e, 0xa2, 0xb8, 0x28, 0xf3, 0xbc, 0xc5, 0xaf, 0x6d, 0x2a, 0x45, 0x34,
+ 0x91, 0x62, 0xf5, 0xe1, 0x66, 0x7f, 0x82, 0xd9, 0xac, 0xc4, 0x29, 0x36,
+ 0xed, 0xcb, 0x8a, 0x97, 0x88, 0x6c, 0x8f, 0xa1, 0x19, 0xbd, 0x04, 0xe1,
+ 0x1c, 0x95, 0x7f, 0x45, 0xe3, 0x8c, 0xda, 0x74, 0xa7, 0xd9, 0x4d, 0x41,
+ 0x34, 0x96, 0x77, 0xe0, 0x68, 0xd7, 0x7b, 0xff, 0x62, 0x1d, 0xa3, 0xaf,
+ 0x12, 0xdc, 0x6a, 0xf1, 0xaf, 0x09, 0xa2, 0xc6, 0x72, 0xa4, 0xbb, 0xcf,
+ 0xd4, 0x96, 0xae, 0x41, 0xfc, 0x77, 0x56, 0xe7, 0xe0, 0x8e, 0x0a, 0x80,
+ 0xd5, 0xc1, 0xb4, 0xfd, 0xa9, 0xf4, 0x8d, 0xc8, 0x26, 0xf8, 0x21, 0x0b,
+ 0x8c, 0xc3, 0x6a, 0x75, 0x46, 0xf2, 0x3f, 0x5c, 0x42, 0xd6, 0xe4, 0x98,
+ 0x73, 0x72, 0x9a, 0x34, 0x71, 0x4f, 0xa2, 0x97, 0x2e, 0x63, 0x1f, 0x38,
+ 0x25, 0x1c, 0xb8, 0xf8, 0xec, 0xc0, 0x60, 0x14, 0x9a, 0x9d, 0x91, 0xc0,
+ 0x0e, 0xbb, 0x23, 0xfc, 0x25, 0x8b, 0x01, 0x20, 0x2d, 0x30, 0x0f, 0x25,
+ 0xa7, 0x0a, 0xbe, 0x91, 0xf3, 0xb5, 0x15, 0x77, 0x07, 0x59, 0x4a, 0x3a,
+ 0xc7, 0x1b, 0xb9, 0xc9, 0x48, 0xa4, 0xfe, 0x05, 0xe2, 0x50, 0x89, 0x26,
+ 0xd8, 0x13, 0xe1, 0xd2, 0xe4, 0x5d, 0x34, 0xa3, 0x8f, 0x99, 0x00, 0xd0,
+ 0x11, 0x13, 0x97, 0x4c, 0x41, 0x2d, 0x63, 0xdf, 0xb6, 0xa6, 0xc1, 0xb5,
+ 0x9f, 0x08, 0xda, 0x44, 0xd1, 0x80, 0x1d, 0xe3, 0x82, 0x12, 0x5e, 0xa8,
+ 0x63, 0x8f, 0x74, 0xf2, 0xab, 0xbb, 0xf6, 0xca, 0x2a, 0x51, 0xa2, 0xc2,
+ 0xcc, 0x85, 0x37, 0x85, 0x97, 0x1a, 0x4c, 0x3e, 0xa1, 0x59, 0xc0, 0xa5,
+ 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72,
+ 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x15, 0xc4, 0x07, 0x64, 0x88,
+ 0x06, 0x82, 0x9c, 0x3c, 0x2d, 0x78, 0x10, 0xb2, 0xe0, 0xd2, 0x9e, 0x71,
+ 0x1d, 0x2f, 0xa4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x4b, 0x45, 0x4b, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x4b, 0x45, 0x4b, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xb1, 0x58, 0xde, 0xa8, 0xfb, 0xf9, 0xd2,
+ 0x48, 0x11, 0x0a, 0x52, 0x68, 0xbf, 0x45, 0x97, 0xde, 0xdf, 0x54, 0xb3,
+ 0x6e, 0x36, 0xc5, 0x3a, 0xbb, 0x40, 0x18, 0x66, 0xa7, 0x0e, 0x5d, 0xb1,
+ 0x7a, 0x56, 0x24, 0xc7, 0x0d, 0x7e, 0x37, 0xba, 0x60, 0x6d, 0xf6, 0x81,
+ 0x0a, 0x3d, 0x42, 0xec, 0x79, 0x49, 0x9a, 0x1c, 0x20, 0x08, 0x17, 0xc7,
+ 0xba, 0x26, 0xc1, 0x71, 0x47, 0xc0, 0xe6, 0x29, 0xb8, 0xd0, 0x4f, 0xe9,
+ 0xd2, 0x6f, 0x18, 0x49, 0x9d, 0xfc, 0x4a, 0xcc, 0x26, 0x74, 0xc6, 0x1e,
+ 0xe7, 0x9c, 0x43, 0x2e, 0x09, 0xe0, 0x5a, 0x60, 0xa2, 0x27, 0xc0, 0x14,
+ 0x32, 0x3d, 0xe4, 0x64, 0xf9, 0x25, 0x6b, 0x9c, 0x7a, 0x01, 0xea, 0xdf,
+ 0x71, 0x26, 0xf8, 0x14, 0x89, 0xa0, 0x80, 0xf4, 0x8a, 0x05, 0x54, 0xc4,
+ 0x9a, 0x7b, 0x32, 0x5e, 0x75, 0x0d, 0x1b, 0x8a, 0x38, 0x5c, 0x64, 0x7c,
+ 0xf0, 0x65, 0x9e, 0xdf, 0x58, 0xaa, 0x71, 0xff, 0xc1, 0x20, 0xe1, 0x4b,
+ 0x48, 0x68, 0x71, 0x4b, 0xfc, 0xef, 0x39, 0x8d, 0xae, 0x58, 0x97, 0x65,
+ 0xb5, 0x44, 0x65, 0x33, 0x93, 0xa6, 0xc2, 0xf7, 0x3c, 0x23, 0x25, 0x47,
+ 0x9c, 0x7b, 0xd8, 0x12, 0xbc, 0xba, 0xce, 0xfe, 0x07, 0xe1, 0xc2, 0x9a,
+ 0x43, 0xb1, 0x09, 0x74, 0xea, 0xdd, 0x81, 0x9a, 0x66, 0xe9, 0x6f, 0x75,
+ 0x8b, 0x63, 0x09, 0x9c, 0xf0, 0x85, 0x72, 0xe5, 0x2a, 0x9f, 0x3e, 0x03,
+ 0xa2, 0x11, 0x73, 0xd5, 0xd0, 0x24, 0x59, 0x74, 0x10, 0x45, 0xcf, 0xe0,
+ 0xb1, 0x3b, 0x35, 0x13, 0x92, 0x60, 0xba, 0x75, 0x1e, 0x39, 0xa2, 0x18,
+ 0xb5, 0x23, 0xf6, 0xc1, 0x74, 0x5d, 0x73, 0x17, 0xea, 0xca, 0xdb, 0xc8,
+ 0xc9, 0x9b, 0xf9, 0x83, 0x44, 0x29, 0x0d, 0xb2, 0xd1, 0x8e, 0x8f, 0xbb,
+ 0xd4, 0x42, 0x43, 0x3d, 0xc1, 0x0f, 0xb0, 0x97, 0xaf, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe7, 0x8d, 0x45, 0x79, 0xdf, 0xb1, 0x92,
+ 0x11, 0x72, 0x87, 0x8b, 0x78, 0xf8, 0xa7, 0x0a, 0x5b, 0x96, 0x87, 0x09,
+ 0x5b, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0xe7, 0x8d, 0x45, 0x79, 0xdf, 0xb1, 0x92, 0x11, 0x72, 0x87,
+ 0x8b, 0x78, 0xf8, 0xa7, 0x0a, 0x5b, 0x96, 0x87, 0x09, 0x5b, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x09,
+ 0x51, 0x16, 0xf4, 0xd7, 0x79, 0xb5, 0xb7, 0x8b, 0x0d, 0x92, 0xc1, 0x9b,
+ 0x0a, 0x19, 0x33, 0x4c, 0xf1, 0x00, 0x6a, 0xcd, 0x8f, 0xa5, 0xd0, 0x6e,
+ 0x3e, 0x69, 0x35, 0x38, 0xb4, 0xb5, 0x44, 0x54, 0x36, 0x19, 0x58, 0xa8,
+ 0xf4, 0x7e, 0xac, 0x8d, 0x41, 0x28, 0x79, 0x67, 0x7f, 0x0e, 0xbc, 0x6f,
+ 0xa8, 0x96, 0x5c, 0x9e, 0xe3, 0x3f, 0x31, 0x4a, 0xa5, 0xb0, 0xfd, 0x1e,
+ 0xbb, 0x0a, 0xc9, 0x53, 0x84, 0xf3, 0xa2, 0xe5, 0x1c, 0x80, 0x0a, 0xc5,
+ 0x78, 0x5f, 0xe2, 0x52, 0xae, 0x36, 0x03, 0x98, 0x73, 0x3c, 0xb0, 0xf3,
+ 0xd9, 0xc2, 0x95, 0x68, 0x03, 0xcd, 0xc7, 0x6b, 0x2f, 0x33, 0x38, 0xb5,
+ 0x5a, 0x9b, 0xe7, 0x29, 0x23, 0xb1, 0x6c, 0xa2, 0x9e, 0x8d, 0xee, 0x85,
+ 0x0d, 0x08, 0x16, 0xdd, 0x64, 0x56, 0x34, 0x81, 0xf1, 0x60, 0x9d, 0x2c,
+ 0xed, 0x12, 0xb4, 0x9a, 0x75, 0xfe, 0xc1, 0x3e, 0x8c, 0xf1, 0x59, 0xbd,
+ 0xf5, 0x35, 0xe2, 0xb6, 0x97, 0xaa, 0x57, 0x9b, 0xef, 0x1d, 0xf5, 0xd7,
+ 0x81, 0x45, 0x41, 0x92, 0x6b, 0x68, 0x8c, 0xeb, 0x78, 0x3f, 0x9e, 0xff,
+ 0x30, 0x4a, 0xd8, 0x84, 0x8d, 0x12, 0x4e, 0xbe, 0x2d, 0x87, 0xc4, 0x3a,
+ 0xc6, 0x28, 0x10, 0x56, 0xab, 0x73, 0xce, 0xb4, 0xcc, 0xe6, 0x97, 0x77,
+ 0xa9, 0x47, 0xa2, 0xd5, 0x05, 0x91, 0x2a, 0xcc, 0xe6, 0x0c, 0xf5, 0xd3,
+ 0xb5, 0x97, 0xb3, 0x5a, 0x9e, 0xa1, 0x60, 0x1a, 0xfb, 0x11, 0x8b, 0xa8,
+ 0x63, 0x4a, 0x2b, 0xc5, 0xb3, 0x4f, 0xff, 0xaf, 0x88, 0x15, 0x6c, 0xe7,
+ 0xba, 0x19, 0x6a, 0xd3, 0xc3, 0xfd, 0x31, 0x96, 0x9c, 0x91, 0xba, 0xe9,
+ 0xea, 0xf5, 0x60, 0xda, 0xe9, 0x11, 0xc7, 0x36, 0x2e, 0xf4, 0x1a, 0xde,
+ 0x1a, 0xf7, 0x38, 0x9b, 0x68, 0xa2, 0x86, 0x1e, 0x34, 0x5d, 0x19, 0x9b,
+ 0x82, 0x03, 0xe5
+};
+unsigned int KEK_auth_len = 2871;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/KEK_delete.h b/components/service/uefi/smm_variable/test/service/auth_vectors/KEK_delete.h
new file mode 100644
index 000000000..7a438a2f5
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/KEK_delete.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char KEK_delete_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0,
+ 0x7a, 0xa6, 0xe6, 0x9b, 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b,
+ 0xc7, 0xa8, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x50, 0x4b, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xcb, 0x94, 0x4f, 0x33, 0x47, 0xe3, 0xb3,
+ 0xd0, 0x34, 0x45, 0x48, 0xea, 0x6c, 0x66, 0x8d, 0xb0, 0x97, 0x41, 0xe8,
+ 0x81, 0x7f, 0xab, 0x83, 0xa5, 0x9f, 0xa6, 0x5d, 0x47, 0x9b, 0x60, 0x55,
+ 0xc3, 0x70, 0x2c, 0xf5, 0x96, 0x9f, 0xa8, 0xdb, 0xc0, 0xca, 0x63, 0x7c,
+ 0x34, 0xed, 0x14, 0x9e, 0xc0, 0xbe, 0xab, 0xe4, 0x3b, 0x73, 0xed, 0x62,
+ 0x24, 0xe8, 0x68, 0xa4, 0x14, 0x10, 0x50, 0x8f, 0x7f, 0x59, 0xad, 0xec,
+ 0x16, 0x60, 0xfe, 0x1f, 0x60, 0x3b, 0x9a, 0x7b, 0x7a, 0xc3, 0x3e, 0xf4,
+ 0xcf, 0x39, 0x27, 0x70, 0xb9, 0xd9, 0x0a, 0x40, 0xc7, 0x7f, 0x41, 0x80,
+ 0xd3, 0xe0, 0x22, 0x15, 0x1a, 0x91, 0x0e, 0x4a, 0xa7, 0x52, 0x33, 0x72,
+ 0xf2, 0x46, 0x03, 0x42, 0x36, 0x85, 0x27, 0xf0, 0x2f, 0x9f, 0x56, 0xa4,
+ 0xd5, 0xdc, 0x00, 0xd5, 0x5e, 0xe5, 0x1a, 0x08, 0xae, 0xdc, 0x80, 0xb9,
+ 0xa4, 0xcf, 0x58, 0xf1, 0xd4, 0x38, 0x5f, 0xe1, 0xff, 0x81, 0x01, 0xff,
+ 0x17, 0x77, 0xe7, 0x4b, 0xee, 0x91, 0xaf, 0x3a, 0xf9, 0x73, 0xd9, 0x6f,
+ 0xe9, 0x22, 0x55, 0x15, 0x17, 0xa9, 0xc9, 0xde, 0xfc, 0x63, 0xfc, 0x84,
+ 0x96, 0xb7, 0xf8, 0x40, 0x63, 0x5f, 0x2c, 0x21, 0x20, 0x1e, 0x37, 0x14,
+ 0x1b, 0x4e, 0x76, 0xec, 0x3a, 0xcb, 0xd5, 0xdc, 0xef, 0x96, 0x37, 0x43,
+ 0x46, 0x4c, 0x2e, 0xf4, 0xcb, 0x58, 0x90, 0x91, 0x35, 0x6d, 0xb5, 0x58,
+ 0xb8, 0xb7, 0x74, 0x72, 0x80, 0x3f, 0xb7, 0xd0, 0x1b, 0xca, 0x47, 0x18,
+ 0xc9, 0x99, 0x4d, 0x74, 0x97, 0x57, 0xc4, 0x2f, 0x2e, 0x2a, 0xd0, 0x95,
+ 0xc2, 0x1e, 0x64, 0x8d, 0xbd, 0xd1, 0x7e, 0xf6, 0x6c, 0x44, 0x01, 0x1f,
+ 0x37, 0xc0, 0x67, 0x7a, 0x78, 0x47, 0x21, 0xb4, 0x0d, 0xc6, 0xab, 0x81,
+ 0x7e, 0x1c, 0x10, 0x5d, 0x01, 0x2e, 0xfe, 0x41, 0x93, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4,
+ 0xbb, 0x06, 0xa7, 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66,
+ 0x08, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4, 0xbb, 0x06, 0xa7,
+ 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66, 0x08, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3a,
+ 0xae, 0xa0, 0xfa, 0x34, 0x4a, 0x52, 0x24, 0x90, 0x3a, 0xba, 0x33, 0x61,
+ 0x0f, 0xc8, 0x6f, 0xbc, 0x72, 0xf8, 0xc3, 0x98, 0x04, 0xe1, 0xcb, 0xf2,
+ 0x82, 0xfd, 0x83, 0x59, 0x51, 0x23, 0x71, 0xf4, 0xce, 0xe9, 0x36, 0x4d,
+ 0x0a, 0xd3, 0x11, 0x6d, 0x51, 0xb7, 0xd1, 0x9f, 0x9b, 0x85, 0x5c, 0x25,
+ 0x11, 0x9c, 0x13, 0xf6, 0x33, 0xd8, 0xa4, 0x27, 0xef, 0x90, 0x56, 0x21,
+ 0xe3, 0x90, 0x10, 0x2b, 0x50, 0x46, 0x6e, 0x8a, 0x84, 0x3e, 0x30, 0x4c,
+ 0xc2, 0xdf, 0x81, 0x60, 0xdf, 0xb8, 0x06, 0xd8, 0x2f, 0xcf, 0x3f, 0xb8,
+ 0xbe, 0x04, 0xa4, 0xbb, 0xba, 0x65, 0x9f, 0x4e, 0xc4, 0x05, 0xbe, 0x9e,
+ 0xfe, 0xa9, 0x0c, 0x06, 0x81, 0xcc, 0xa4, 0x66, 0xb0, 0x14, 0x48, 0xc9,
+ 0x24, 0x88, 0xd8, 0xdc, 0xf2, 0x5c, 0xb5, 0x59, 0x66, 0x4f, 0xc6, 0xa4,
+ 0xa3, 0x96, 0xa8, 0x48, 0x3b, 0x43, 0xff, 0xe0, 0x10, 0x53, 0x79, 0x47,
+ 0x74, 0xe8, 0xbc, 0xa9, 0x4f, 0x8e, 0x1f, 0xfb, 0xf8, 0xad, 0x8d, 0x10,
+ 0x80, 0x8f, 0x80, 0xf8, 0x5b, 0x36, 0xff, 0x60, 0x0b, 0x3f, 0xb2, 0x2f,
+ 0x46, 0x27, 0x43, 0x00, 0x1a, 0x0d, 0xb8, 0x91, 0x4e, 0x84, 0xb1, 0x94,
+ 0xc2, 0xca, 0xd6, 0x36, 0x4d, 0xc6, 0xda, 0x53, 0x71, 0xcc, 0xc8, 0x8e,
+ 0x9c, 0xdb, 0x31, 0xbb, 0x93, 0x49, 0xa7, 0xf4, 0x0b, 0x19, 0xcb, 0xaa,
+ 0x2b, 0x0c, 0xf4, 0xc7, 0x59, 0x8a, 0xc6, 0x59, 0x0b, 0x1d, 0x2f, 0xc3,
+ 0xcf, 0x06, 0xcf, 0x2e, 0x6b, 0x15, 0x6f, 0xba, 0xd1, 0xfa, 0x7d, 0x7f,
+ 0xaa, 0x99, 0x09, 0x63, 0xa8, 0xdd, 0x6c, 0xdb, 0x6a, 0x5e, 0x00, 0x5e,
+ 0x89, 0x11, 0xe3, 0xbd, 0xf6, 0xcb, 0x13, 0x89, 0x6a, 0xb8, 0x7e, 0x89,
+ 0xbc, 0xa5, 0xec, 0x68, 0x85, 0xf0, 0xaa, 0x05, 0x91, 0xc1, 0x79, 0xa1,
+ 0x1c, 0x9d, 0x32, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x31, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0, 0x7a, 0xa6, 0xe6, 0x9b,
+ 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b, 0xc7, 0xa8, 0x37, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x79, 0xb7, 0xf1,
+ 0xd7, 0x10, 0x57, 0xa4, 0x67, 0x2a, 0x91, 0xef, 0x0a, 0xc7, 0x5d, 0xab,
+ 0x08, 0x42, 0x15, 0xc0, 0x26, 0xe7, 0x5d, 0xf1, 0xeb, 0xb1, 0x12, 0xc6,
+ 0x2e, 0x06, 0xef, 0x46, 0x84, 0x4c, 0xde, 0x5e, 0xcb, 0x15, 0xe0, 0x19,
+ 0x9e, 0x90, 0xdf, 0x92, 0x11, 0x55, 0xb5, 0x50, 0x34, 0xf4, 0xfd, 0x6c,
+ 0x76, 0x08, 0xb6, 0x0b, 0xd8, 0x82, 0x4a, 0x8c, 0xc5, 0x4f, 0xc8, 0x56,
+ 0xbe, 0xca, 0xac, 0xcb, 0xe9, 0x11, 0x28, 0xf5, 0xde, 0x21, 0x37, 0x2c,
+ 0x5b, 0xaa, 0x7f, 0x8a, 0x27, 0xd7, 0xad, 0xba, 0xb6, 0x6d, 0x98, 0x59,
+ 0x04, 0xd9, 0x05, 0xa1, 0xab, 0x50, 0xc9, 0x3c, 0xaf, 0x9f, 0x00, 0xad,
+ 0x06, 0x76, 0x07, 0x95, 0x6b, 0x34, 0xf3, 0xbe, 0xe3, 0xa1, 0xc2, 0xf9,
+ 0x03, 0xee, 0x35, 0xa8, 0xa8, 0xbb, 0x9b, 0xdf, 0xc6, 0x41, 0xff, 0xd1,
+ 0x97, 0x00, 0xfd, 0x58, 0xb0, 0xcc, 0x63, 0x5f, 0x91, 0xc0, 0xb7, 0x4d,
+ 0xb1, 0xbd, 0x57, 0xfc, 0xfe, 0xa3, 0x6b, 0xd8, 0xdf, 0xd4, 0x57, 0x12,
+ 0x31, 0x0b, 0x64, 0xd8, 0xd9, 0xcd, 0xde, 0xa6, 0x6c, 0x7b, 0xb3, 0x05,
+ 0x25, 0xd2, 0x0a, 0x9f, 0xc1, 0xf3, 0xcb, 0xa7, 0x7d, 0x79, 0x6a, 0x3d,
+ 0xdd, 0x16, 0xac, 0xdc, 0x46, 0xb4, 0x76, 0x7f, 0xe5, 0x8b, 0x7c, 0xc4,
+ 0xc9, 0x59, 0x40, 0xa6, 0x75, 0x19, 0xb6, 0xa1, 0x43, 0xa6, 0x79, 0x2c,
+ 0xa3, 0x47, 0x02, 0x1c, 0xdb, 0x39, 0xa0, 0x4b, 0x94, 0xfa, 0x0c, 0x56,
+ 0xea, 0x32, 0x2e, 0x26, 0x44, 0xf6, 0x22, 0xdc, 0x12, 0x0d, 0x91, 0x98,
+ 0x2d, 0x28, 0x7c, 0x68, 0xc8, 0x2f, 0xbd, 0x7b, 0xa2, 0x6d, 0xfa, 0x77,
+ 0xd6, 0xf3, 0xcd, 0xb7, 0xd6, 0x0e, 0xd7, 0x4f, 0x8c, 0x13, 0xf6, 0x82,
+ 0x51, 0x03, 0xd6, 0x09, 0xfd, 0x82, 0xd7, 0x7e, 0xa1, 0xbe, 0x10, 0x0a,
+ 0x7c
+};
+unsigned int KEK_delete_auth_len = 1225;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/PK1.h b/components/service/uefi/smm_variable/test/service/auth_vectors/PK1.h
new file mode 100644
index 000000000..fd8817a7d
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/PK1.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char PK1_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0,
+ 0x7a, 0xa6, 0xe6, 0x9b, 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b,
+ 0xc7, 0xa8, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x50, 0x4b, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xcb, 0x94, 0x4f, 0x33, 0x47, 0xe3, 0xb3,
+ 0xd0, 0x34, 0x45, 0x48, 0xea, 0x6c, 0x66, 0x8d, 0xb0, 0x97, 0x41, 0xe8,
+ 0x81, 0x7f, 0xab, 0x83, 0xa5, 0x9f, 0xa6, 0x5d, 0x47, 0x9b, 0x60, 0x55,
+ 0xc3, 0x70, 0x2c, 0xf5, 0x96, 0x9f, 0xa8, 0xdb, 0xc0, 0xca, 0x63, 0x7c,
+ 0x34, 0xed, 0x14, 0x9e, 0xc0, 0xbe, 0xab, 0xe4, 0x3b, 0x73, 0xed, 0x62,
+ 0x24, 0xe8, 0x68, 0xa4, 0x14, 0x10, 0x50, 0x8f, 0x7f, 0x59, 0xad, 0xec,
+ 0x16, 0x60, 0xfe, 0x1f, 0x60, 0x3b, 0x9a, 0x7b, 0x7a, 0xc3, 0x3e, 0xf4,
+ 0xcf, 0x39, 0x27, 0x70, 0xb9, 0xd9, 0x0a, 0x40, 0xc7, 0x7f, 0x41, 0x80,
+ 0xd3, 0xe0, 0x22, 0x15, 0x1a, 0x91, 0x0e, 0x4a, 0xa7, 0x52, 0x33, 0x72,
+ 0xf2, 0x46, 0x03, 0x42, 0x36, 0x85, 0x27, 0xf0, 0x2f, 0x9f, 0x56, 0xa4,
+ 0xd5, 0xdc, 0x00, 0xd5, 0x5e, 0xe5, 0x1a, 0x08, 0xae, 0xdc, 0x80, 0xb9,
+ 0xa4, 0xcf, 0x58, 0xf1, 0xd4, 0x38, 0x5f, 0xe1, 0xff, 0x81, 0x01, 0xff,
+ 0x17, 0x77, 0xe7, 0x4b, 0xee, 0x91, 0xaf, 0x3a, 0xf9, 0x73, 0xd9, 0x6f,
+ 0xe9, 0x22, 0x55, 0x15, 0x17, 0xa9, 0xc9, 0xde, 0xfc, 0x63, 0xfc, 0x84,
+ 0x96, 0xb7, 0xf8, 0x40, 0x63, 0x5f, 0x2c, 0x21, 0x20, 0x1e, 0x37, 0x14,
+ 0x1b, 0x4e, 0x76, 0xec, 0x3a, 0xcb, 0xd5, 0xdc, 0xef, 0x96, 0x37, 0x43,
+ 0x46, 0x4c, 0x2e, 0xf4, 0xcb, 0x58, 0x90, 0x91, 0x35, 0x6d, 0xb5, 0x58,
+ 0xb8, 0xb7, 0x74, 0x72, 0x80, 0x3f, 0xb7, 0xd0, 0x1b, 0xca, 0x47, 0x18,
+ 0xc9, 0x99, 0x4d, 0x74, 0x97, 0x57, 0xc4, 0x2f, 0x2e, 0x2a, 0xd0, 0x95,
+ 0xc2, 0x1e, 0x64, 0x8d, 0xbd, 0xd1, 0x7e, 0xf6, 0x6c, 0x44, 0x01, 0x1f,
+ 0x37, 0xc0, 0x67, 0x7a, 0x78, 0x47, 0x21, 0xb4, 0x0d, 0xc6, 0xab, 0x81,
+ 0x7e, 0x1c, 0x10, 0x5d, 0x01, 0x2e, 0xfe, 0x41, 0x93, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4,
+ 0xbb, 0x06, 0xa7, 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66,
+ 0x08, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4, 0xbb, 0x06, 0xa7,
+ 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66, 0x08, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3a,
+ 0xae, 0xa0, 0xfa, 0x34, 0x4a, 0x52, 0x24, 0x90, 0x3a, 0xba, 0x33, 0x61,
+ 0x0f, 0xc8, 0x6f, 0xbc, 0x72, 0xf8, 0xc3, 0x98, 0x04, 0xe1, 0xcb, 0xf2,
+ 0x82, 0xfd, 0x83, 0x59, 0x51, 0x23, 0x71, 0xf4, 0xce, 0xe9, 0x36, 0x4d,
+ 0x0a, 0xd3, 0x11, 0x6d, 0x51, 0xb7, 0xd1, 0x9f, 0x9b, 0x85, 0x5c, 0x25,
+ 0x11, 0x9c, 0x13, 0xf6, 0x33, 0xd8, 0xa4, 0x27, 0xef, 0x90, 0x56, 0x21,
+ 0xe3, 0x90, 0x10, 0x2b, 0x50, 0x46, 0x6e, 0x8a, 0x84, 0x3e, 0x30, 0x4c,
+ 0xc2, 0xdf, 0x81, 0x60, 0xdf, 0xb8, 0x06, 0xd8, 0x2f, 0xcf, 0x3f, 0xb8,
+ 0xbe, 0x04, 0xa4, 0xbb, 0xba, 0x65, 0x9f, 0x4e, 0xc4, 0x05, 0xbe, 0x9e,
+ 0xfe, 0xa9, 0x0c, 0x06, 0x81, 0xcc, 0xa4, 0x66, 0xb0, 0x14, 0x48, 0xc9,
+ 0x24, 0x88, 0xd8, 0xdc, 0xf2, 0x5c, 0xb5, 0x59, 0x66, 0x4f, 0xc6, 0xa4,
+ 0xa3, 0x96, 0xa8, 0x48, 0x3b, 0x43, 0xff, 0xe0, 0x10, 0x53, 0x79, 0x47,
+ 0x74, 0xe8, 0xbc, 0xa9, 0x4f, 0x8e, 0x1f, 0xfb, 0xf8, 0xad, 0x8d, 0x10,
+ 0x80, 0x8f, 0x80, 0xf8, 0x5b, 0x36, 0xff, 0x60, 0x0b, 0x3f, 0xb2, 0x2f,
+ 0x46, 0x27, 0x43, 0x00, 0x1a, 0x0d, 0xb8, 0x91, 0x4e, 0x84, 0xb1, 0x94,
+ 0xc2, 0xca, 0xd6, 0x36, 0x4d, 0xc6, 0xda, 0x53, 0x71, 0xcc, 0xc8, 0x8e,
+ 0x9c, 0xdb, 0x31, 0xbb, 0x93, 0x49, 0xa7, 0xf4, 0x0b, 0x19, 0xcb, 0xaa,
+ 0x2b, 0x0c, 0xf4, 0xc7, 0x59, 0x8a, 0xc6, 0x59, 0x0b, 0x1d, 0x2f, 0xc3,
+ 0xcf, 0x06, 0xcf, 0x2e, 0x6b, 0x15, 0x6f, 0xba, 0xd1, 0xfa, 0x7d, 0x7f,
+ 0xaa, 0x99, 0x09, 0x63, 0xa8, 0xdd, 0x6c, 0xdb, 0x6a, 0x5e, 0x00, 0x5e,
+ 0x89, 0x11, 0xe3, 0xbd, 0xf6, 0xcb, 0x13, 0x89, 0x6a, 0xb8, 0x7e, 0x89,
+ 0xbc, 0xa5, 0xec, 0x68, 0x85, 0xf0, 0xaa, 0x05, 0x91, 0xc1, 0x79, 0xa1,
+ 0x1c, 0x9d, 0x32, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x31, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0, 0x7a, 0xa6, 0xe6, 0x9b,
+ 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b, 0xc7, 0xa8, 0x37, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x57, 0x48, 0xaf,
+ 0x74, 0x8c, 0x31, 0x13, 0x78, 0x5a, 0x3f, 0x7f, 0xe2, 0xbb, 0x91, 0x66,
+ 0x4a, 0xc7, 0x05, 0x87, 0xc5, 0x9c, 0x20, 0x11, 0xee, 0x1b, 0x1b, 0x7d,
+ 0xcf, 0xe6, 0xb0, 0x90, 0xf5, 0x42, 0xdb, 0x78, 0x23, 0x96, 0x00, 0x34,
+ 0xa9, 0x5e, 0xdf, 0x9c, 0xb2, 0x5c, 0xf6, 0xa3, 0xc1, 0xdf, 0x8b, 0x12,
+ 0x5e, 0x34, 0x27, 0x5e, 0xdb, 0xab, 0xc5, 0x13, 0x66, 0x93, 0xdd, 0xec,
+ 0x0e, 0x5d, 0xfe, 0x4c, 0x23, 0x3b, 0xbd, 0x94, 0x99, 0x88, 0x61, 0x05,
+ 0x0b, 0xd2, 0xef, 0x18, 0xd2, 0xe1, 0xe7, 0x58, 0xff, 0x27, 0x1c, 0x3a,
+ 0x66, 0x44, 0xe4, 0x24, 0xeb, 0x66, 0xc6, 0x8f, 0x38, 0x9f, 0x4e, 0xda,
+ 0x96, 0xe4, 0xdb, 0x43, 0xb5, 0x13, 0xb9, 0xbe, 0xdc, 0xd4, 0x7a, 0xed,
+ 0x6a, 0xcd, 0x98, 0x5d, 0x2b, 0x51, 0xb5, 0xd8, 0xe3, 0x10, 0xc9, 0x70,
+ 0xa1, 0xaa, 0x68, 0x88, 0x21, 0x6f, 0x2e, 0x9c, 0xa8, 0x03, 0x7d, 0x22,
+ 0x06, 0xa0, 0x24, 0x2b, 0x22, 0x55, 0x3f, 0x91, 0x44, 0xe5, 0x28, 0x39,
+ 0x05, 0x2d, 0xa0, 0xe0, 0xcf, 0x85, 0xfa, 0xb6, 0x7d, 0x8f, 0x02, 0x7f,
+ 0xd7, 0x42, 0xed, 0x07, 0xf7, 0xa0, 0xae, 0x61, 0x85, 0x40, 0x4b, 0xe5,
+ 0x3e, 0x33, 0xc8, 0xeb, 0xb5, 0xed, 0x8f, 0x9a, 0xb7, 0xd5, 0x1b, 0xef,
+ 0x86, 0x76, 0xe4, 0x7b, 0x61, 0x18, 0x5f, 0xac, 0xb0, 0x19, 0xc4, 0x45,
+ 0x16, 0xd0, 0xed, 0xe2, 0x61, 0x61, 0xec, 0xca, 0xd1, 0x02, 0x0d, 0xbf,
+ 0xba, 0x72, 0x0b, 0x45, 0xf9, 0xc3, 0xb0, 0xfd, 0x16, 0xd5, 0x2c, 0x32,
+ 0xc1, 0x48, 0x2e, 0x9e, 0x7f, 0x62, 0x52, 0x39, 0x30, 0x3e, 0xbf, 0x55,
+ 0xf9, 0xa5, 0x11, 0x9e, 0x12, 0xda, 0x20, 0x9b, 0x63, 0xad, 0xc3, 0x82,
+ 0x49, 0x8d, 0x49, 0xa8, 0x22, 0x62, 0xc9, 0xac, 0x08, 0x81, 0x51, 0x98,
+ 0xe1, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab,
+ 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03,
+ 0x07, 0x30, 0x82, 0x01, 0xef, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+ 0x71, 0x90, 0xc6, 0x30, 0xd0, 0x7a, 0xa6, 0xe6, 0x9b, 0x3f, 0x3b, 0x01,
+ 0x47, 0x16, 0xad, 0x20, 0x9b, 0xc7, 0xa8, 0x37, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x1e, 0x17, 0x0d,
+ 0x32, 0x34, 0x30, 0x31, 0x32, 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38,
+ 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32,
+ 0x30, 0x30, 0x38, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+ 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xcb, 0x94,
+ 0x4f, 0x33, 0x47, 0xe3, 0xb3, 0xd0, 0x34, 0x45, 0x48, 0xea, 0x6c, 0x66,
+ 0x8d, 0xb0, 0x97, 0x41, 0xe8, 0x81, 0x7f, 0xab, 0x83, 0xa5, 0x9f, 0xa6,
+ 0x5d, 0x47, 0x9b, 0x60, 0x55, 0xc3, 0x70, 0x2c, 0xf5, 0x96, 0x9f, 0xa8,
+ 0xdb, 0xc0, 0xca, 0x63, 0x7c, 0x34, 0xed, 0x14, 0x9e, 0xc0, 0xbe, 0xab,
+ 0xe4, 0x3b, 0x73, 0xed, 0x62, 0x24, 0xe8, 0x68, 0xa4, 0x14, 0x10, 0x50,
+ 0x8f, 0x7f, 0x59, 0xad, 0xec, 0x16, 0x60, 0xfe, 0x1f, 0x60, 0x3b, 0x9a,
+ 0x7b, 0x7a, 0xc3, 0x3e, 0xf4, 0xcf, 0x39, 0x27, 0x70, 0xb9, 0xd9, 0x0a,
+ 0x40, 0xc7, 0x7f, 0x41, 0x80, 0xd3, 0xe0, 0x22, 0x15, 0x1a, 0x91, 0x0e,
+ 0x4a, 0xa7, 0x52, 0x33, 0x72, 0xf2, 0x46, 0x03, 0x42, 0x36, 0x85, 0x27,
+ 0xf0, 0x2f, 0x9f, 0x56, 0xa4, 0xd5, 0xdc, 0x00, 0xd5, 0x5e, 0xe5, 0x1a,
+ 0x08, 0xae, 0xdc, 0x80, 0xb9, 0xa4, 0xcf, 0x58, 0xf1, 0xd4, 0x38, 0x5f,
+ 0xe1, 0xff, 0x81, 0x01, 0xff, 0x17, 0x77, 0xe7, 0x4b, 0xee, 0x91, 0xaf,
+ 0x3a, 0xf9, 0x73, 0xd9, 0x6f, 0xe9, 0x22, 0x55, 0x15, 0x17, 0xa9, 0xc9,
+ 0xde, 0xfc, 0x63, 0xfc, 0x84, 0x96, 0xb7, 0xf8, 0x40, 0x63, 0x5f, 0x2c,
+ 0x21, 0x20, 0x1e, 0x37, 0x14, 0x1b, 0x4e, 0x76, 0xec, 0x3a, 0xcb, 0xd5,
+ 0xdc, 0xef, 0x96, 0x37, 0x43, 0x46, 0x4c, 0x2e, 0xf4, 0xcb, 0x58, 0x90,
+ 0x91, 0x35, 0x6d, 0xb5, 0x58, 0xb8, 0xb7, 0x74, 0x72, 0x80, 0x3f, 0xb7,
+ 0xd0, 0x1b, 0xca, 0x47, 0x18, 0xc9, 0x99, 0x4d, 0x74, 0x97, 0x57, 0xc4,
+ 0x2f, 0x2e, 0x2a, 0xd0, 0x95, 0xc2, 0x1e, 0x64, 0x8d, 0xbd, 0xd1, 0x7e,
+ 0xf6, 0x6c, 0x44, 0x01, 0x1f, 0x37, 0xc0, 0x67, 0x7a, 0x78, 0x47, 0x21,
+ 0xb4, 0x0d, 0xc6, 0xab, 0x81, 0x7e, 0x1c, 0x10, 0x5d, 0x01, 0x2e, 0xfe,
+ 0x41, 0x93, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30,
+ 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x18, 0x51,
+ 0xee, 0x40, 0x22, 0xae, 0xa4, 0xbb, 0x06, 0xa7, 0xf2, 0xb0, 0x08, 0xf9,
+ 0x5e, 0x89, 0x08, 0x08, 0x66, 0x08, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22,
+ 0xae, 0xa4, 0xbb, 0x06, 0xa7, 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08,
+ 0x08, 0x66, 0x08, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+ 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x01, 0x00, 0x3a, 0xae, 0xa0, 0xfa, 0x34, 0x4a, 0x52, 0x24,
+ 0x90, 0x3a, 0xba, 0x33, 0x61, 0x0f, 0xc8, 0x6f, 0xbc, 0x72, 0xf8, 0xc3,
+ 0x98, 0x04, 0xe1, 0xcb, 0xf2, 0x82, 0xfd, 0x83, 0x59, 0x51, 0x23, 0x71,
+ 0xf4, 0xce, 0xe9, 0x36, 0x4d, 0x0a, 0xd3, 0x11, 0x6d, 0x51, 0xb7, 0xd1,
+ 0x9f, 0x9b, 0x85, 0x5c, 0x25, 0x11, 0x9c, 0x13, 0xf6, 0x33, 0xd8, 0xa4,
+ 0x27, 0xef, 0x90, 0x56, 0x21, 0xe3, 0x90, 0x10, 0x2b, 0x50, 0x46, 0x6e,
+ 0x8a, 0x84, 0x3e, 0x30, 0x4c, 0xc2, 0xdf, 0x81, 0x60, 0xdf, 0xb8, 0x06,
+ 0xd8, 0x2f, 0xcf, 0x3f, 0xb8, 0xbe, 0x04, 0xa4, 0xbb, 0xba, 0x65, 0x9f,
+ 0x4e, 0xc4, 0x05, 0xbe, 0x9e, 0xfe, 0xa9, 0x0c, 0x06, 0x81, 0xcc, 0xa4,
+ 0x66, 0xb0, 0x14, 0x48, 0xc9, 0x24, 0x88, 0xd8, 0xdc, 0xf2, 0x5c, 0xb5,
+ 0x59, 0x66, 0x4f, 0xc6, 0xa4, 0xa3, 0x96, 0xa8, 0x48, 0x3b, 0x43, 0xff,
+ 0xe0, 0x10, 0x53, 0x79, 0x47, 0x74, 0xe8, 0xbc, 0xa9, 0x4f, 0x8e, 0x1f,
+ 0xfb, 0xf8, 0xad, 0x8d, 0x10, 0x80, 0x8f, 0x80, 0xf8, 0x5b, 0x36, 0xff,
+ 0x60, 0x0b, 0x3f, 0xb2, 0x2f, 0x46, 0x27, 0x43, 0x00, 0x1a, 0x0d, 0xb8,
+ 0x91, 0x4e, 0x84, 0xb1, 0x94, 0xc2, 0xca, 0xd6, 0x36, 0x4d, 0xc6, 0xda,
+ 0x53, 0x71, 0xcc, 0xc8, 0x8e, 0x9c, 0xdb, 0x31, 0xbb, 0x93, 0x49, 0xa7,
+ 0xf4, 0x0b, 0x19, 0xcb, 0xaa, 0x2b, 0x0c, 0xf4, 0xc7, 0x59, 0x8a, 0xc6,
+ 0x59, 0x0b, 0x1d, 0x2f, 0xc3, 0xcf, 0x06, 0xcf, 0x2e, 0x6b, 0x15, 0x6f,
+ 0xba, 0xd1, 0xfa, 0x7d, 0x7f, 0xaa, 0x99, 0x09, 0x63, 0xa8, 0xdd, 0x6c,
+ 0xdb, 0x6a, 0x5e, 0x00, 0x5e, 0x89, 0x11, 0xe3, 0xbd, 0xf6, 0xcb, 0x13,
+ 0x89, 0x6a, 0xb8, 0x7e, 0x89, 0xbc, 0xa5, 0xec, 0x68, 0x85, 0xf0, 0xaa,
+ 0x05, 0x91, 0xc1, 0x79, 0xa1, 0x1c, 0x9d, 0x32
+};
+unsigned int PK1_auth_len = 2048;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/PK1_delete.h b/components/service/uefi/smm_variable/test/service/auth_vectors/PK1_delete.h
new file mode 100644
index 000000000..e6c399235
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/PK1_delete.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char PK1_delete_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0,
+ 0x7a, 0xa6, 0xe6, 0x9b, 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b,
+ 0xc7, 0xa8, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x50, 0x4b, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xcb, 0x94, 0x4f, 0x33, 0x47, 0xe3, 0xb3,
+ 0xd0, 0x34, 0x45, 0x48, 0xea, 0x6c, 0x66, 0x8d, 0xb0, 0x97, 0x41, 0xe8,
+ 0x81, 0x7f, 0xab, 0x83, 0xa5, 0x9f, 0xa6, 0x5d, 0x47, 0x9b, 0x60, 0x55,
+ 0xc3, 0x70, 0x2c, 0xf5, 0x96, 0x9f, 0xa8, 0xdb, 0xc0, 0xca, 0x63, 0x7c,
+ 0x34, 0xed, 0x14, 0x9e, 0xc0, 0xbe, 0xab, 0xe4, 0x3b, 0x73, 0xed, 0x62,
+ 0x24, 0xe8, 0x68, 0xa4, 0x14, 0x10, 0x50, 0x8f, 0x7f, 0x59, 0xad, 0xec,
+ 0x16, 0x60, 0xfe, 0x1f, 0x60, 0x3b, 0x9a, 0x7b, 0x7a, 0xc3, 0x3e, 0xf4,
+ 0xcf, 0x39, 0x27, 0x70, 0xb9, 0xd9, 0x0a, 0x40, 0xc7, 0x7f, 0x41, 0x80,
+ 0xd3, 0xe0, 0x22, 0x15, 0x1a, 0x91, 0x0e, 0x4a, 0xa7, 0x52, 0x33, 0x72,
+ 0xf2, 0x46, 0x03, 0x42, 0x36, 0x85, 0x27, 0xf0, 0x2f, 0x9f, 0x56, 0xa4,
+ 0xd5, 0xdc, 0x00, 0xd5, 0x5e, 0xe5, 0x1a, 0x08, 0xae, 0xdc, 0x80, 0xb9,
+ 0xa4, 0xcf, 0x58, 0xf1, 0xd4, 0x38, 0x5f, 0xe1, 0xff, 0x81, 0x01, 0xff,
+ 0x17, 0x77, 0xe7, 0x4b, 0xee, 0x91, 0xaf, 0x3a, 0xf9, 0x73, 0xd9, 0x6f,
+ 0xe9, 0x22, 0x55, 0x15, 0x17, 0xa9, 0xc9, 0xde, 0xfc, 0x63, 0xfc, 0x84,
+ 0x96, 0xb7, 0xf8, 0x40, 0x63, 0x5f, 0x2c, 0x21, 0x20, 0x1e, 0x37, 0x14,
+ 0x1b, 0x4e, 0x76, 0xec, 0x3a, 0xcb, 0xd5, 0xdc, 0xef, 0x96, 0x37, 0x43,
+ 0x46, 0x4c, 0x2e, 0xf4, 0xcb, 0x58, 0x90, 0x91, 0x35, 0x6d, 0xb5, 0x58,
+ 0xb8, 0xb7, 0x74, 0x72, 0x80, 0x3f, 0xb7, 0xd0, 0x1b, 0xca, 0x47, 0x18,
+ 0xc9, 0x99, 0x4d, 0x74, 0x97, 0x57, 0xc4, 0x2f, 0x2e, 0x2a, 0xd0, 0x95,
+ 0xc2, 0x1e, 0x64, 0x8d, 0xbd, 0xd1, 0x7e, 0xf6, 0x6c, 0x44, 0x01, 0x1f,
+ 0x37, 0xc0, 0x67, 0x7a, 0x78, 0x47, 0x21, 0xb4, 0x0d, 0xc6, 0xab, 0x81,
+ 0x7e, 0x1c, 0x10, 0x5d, 0x01, 0x2e, 0xfe, 0x41, 0x93, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4,
+ 0xbb, 0x06, 0xa7, 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66,
+ 0x08, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4, 0xbb, 0x06, 0xa7,
+ 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66, 0x08, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3a,
+ 0xae, 0xa0, 0xfa, 0x34, 0x4a, 0x52, 0x24, 0x90, 0x3a, 0xba, 0x33, 0x61,
+ 0x0f, 0xc8, 0x6f, 0xbc, 0x72, 0xf8, 0xc3, 0x98, 0x04, 0xe1, 0xcb, 0xf2,
+ 0x82, 0xfd, 0x83, 0x59, 0x51, 0x23, 0x71, 0xf4, 0xce, 0xe9, 0x36, 0x4d,
+ 0x0a, 0xd3, 0x11, 0x6d, 0x51, 0xb7, 0xd1, 0x9f, 0x9b, 0x85, 0x5c, 0x25,
+ 0x11, 0x9c, 0x13, 0xf6, 0x33, 0xd8, 0xa4, 0x27, 0xef, 0x90, 0x56, 0x21,
+ 0xe3, 0x90, 0x10, 0x2b, 0x50, 0x46, 0x6e, 0x8a, 0x84, 0x3e, 0x30, 0x4c,
+ 0xc2, 0xdf, 0x81, 0x60, 0xdf, 0xb8, 0x06, 0xd8, 0x2f, 0xcf, 0x3f, 0xb8,
+ 0xbe, 0x04, 0xa4, 0xbb, 0xba, 0x65, 0x9f, 0x4e, 0xc4, 0x05, 0xbe, 0x9e,
+ 0xfe, 0xa9, 0x0c, 0x06, 0x81, 0xcc, 0xa4, 0x66, 0xb0, 0x14, 0x48, 0xc9,
+ 0x24, 0x88, 0xd8, 0xdc, 0xf2, 0x5c, 0xb5, 0x59, 0x66, 0x4f, 0xc6, 0xa4,
+ 0xa3, 0x96, 0xa8, 0x48, 0x3b, 0x43, 0xff, 0xe0, 0x10, 0x53, 0x79, 0x47,
+ 0x74, 0xe8, 0xbc, 0xa9, 0x4f, 0x8e, 0x1f, 0xfb, 0xf8, 0xad, 0x8d, 0x10,
+ 0x80, 0x8f, 0x80, 0xf8, 0x5b, 0x36, 0xff, 0x60, 0x0b, 0x3f, 0xb2, 0x2f,
+ 0x46, 0x27, 0x43, 0x00, 0x1a, 0x0d, 0xb8, 0x91, 0x4e, 0x84, 0xb1, 0x94,
+ 0xc2, 0xca, 0xd6, 0x36, 0x4d, 0xc6, 0xda, 0x53, 0x71, 0xcc, 0xc8, 0x8e,
+ 0x9c, 0xdb, 0x31, 0xbb, 0x93, 0x49, 0xa7, 0xf4, 0x0b, 0x19, 0xcb, 0xaa,
+ 0x2b, 0x0c, 0xf4, 0xc7, 0x59, 0x8a, 0xc6, 0x59, 0x0b, 0x1d, 0x2f, 0xc3,
+ 0xcf, 0x06, 0xcf, 0x2e, 0x6b, 0x15, 0x6f, 0xba, 0xd1, 0xfa, 0x7d, 0x7f,
+ 0xaa, 0x99, 0x09, 0x63, 0xa8, 0xdd, 0x6c, 0xdb, 0x6a, 0x5e, 0x00, 0x5e,
+ 0x89, 0x11, 0xe3, 0xbd, 0xf6, 0xcb, 0x13, 0x89, 0x6a, 0xb8, 0x7e, 0x89,
+ 0xbc, 0xa5, 0xec, 0x68, 0x85, 0xf0, 0xaa, 0x05, 0x91, 0xc1, 0x79, 0xa1,
+ 0x1c, 0x9d, 0x32, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x31, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0, 0x7a, 0xa6, 0xe6, 0x9b,
+ 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b, 0xc7, 0xa8, 0x37, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xaf, 0x30, 0x48,
+ 0x00, 0x6c, 0x9a, 0xa0, 0x99, 0xb3, 0x46, 0x88, 0xa5, 0x59, 0x23, 0x2e,
+ 0x60, 0x5f, 0x2d, 0xda, 0x31, 0x3a, 0x34, 0x96, 0x2e, 0xd3, 0xe0, 0x07,
+ 0xaa, 0x5f, 0x31, 0x8c, 0xa6, 0xa8, 0x09, 0x30, 0x1e, 0x9b, 0xad, 0x39,
+ 0xff, 0x13, 0x7e, 0x01, 0x82, 0x79, 0xb4, 0x91, 0xea, 0x73, 0x6d, 0x61,
+ 0x98, 0x1f, 0xb6, 0x4a, 0xf6, 0x88, 0x78, 0xaf, 0xad, 0x5b, 0x15, 0xb4,
+ 0x12, 0x41, 0x45, 0x70, 0xb5, 0xf5, 0x07, 0xf9, 0x8a, 0x68, 0xd0, 0xfc,
+ 0xcc, 0x4d, 0x2a, 0x78, 0x54, 0x38, 0xa3, 0x38, 0x85, 0xa9, 0x25, 0x38,
+ 0xb4, 0xb0, 0xcd, 0x4e, 0x04, 0xc6, 0x5c, 0xb6, 0x15, 0x86, 0x35, 0xb8,
+ 0x30, 0x8b, 0x43, 0x4a, 0x06, 0xde, 0x4d, 0x4f, 0xc5, 0x8a, 0x63, 0xd7,
+ 0x2d, 0x31, 0xf2, 0x4d, 0x59, 0xf7, 0x74, 0xdd, 0x33, 0x6e, 0x3d, 0x9a,
+ 0xe6, 0xc5, 0x51, 0xc0, 0x64, 0x89, 0x4e, 0x64, 0xaa, 0x6b, 0xf0, 0x35,
+ 0x91, 0xf5, 0x16, 0x04, 0xee, 0xc4, 0xd9, 0x97, 0x38, 0x55, 0x5a, 0x4b,
+ 0x1b, 0x17, 0x91, 0x6b, 0x28, 0xd6, 0xa5, 0xb6, 0xc4, 0x9b, 0xc7, 0xfe,
+ 0x5d, 0x1d, 0xa2, 0x5e, 0xb2, 0x1d, 0xf3, 0x50, 0x2b, 0x45, 0x3f, 0xdd,
+ 0xbc, 0x2e, 0x8a, 0xa2, 0x04, 0x03, 0xcf, 0xbf, 0xf5, 0x59, 0x0a, 0xbf,
+ 0x5b, 0x76, 0xe3, 0x2a, 0x34, 0x26, 0x0c, 0x74, 0x88, 0xfe, 0x2a, 0x07,
+ 0x95, 0x82, 0x05, 0x37, 0x8c, 0xe4, 0xd6, 0x90, 0x21, 0x22, 0xdc, 0xc0,
+ 0x35, 0xea, 0xc4, 0xd6, 0x8b, 0xe2, 0xdc, 0x95, 0xe0, 0x12, 0x51, 0xf9,
+ 0xbe, 0x1d, 0xb6, 0x93, 0x7f, 0x34, 0x02, 0xc7, 0x1d, 0x14, 0x27, 0xd1,
+ 0xf3, 0x15, 0x63, 0x95, 0x48, 0x20, 0x9a, 0xcf, 0x56, 0x83, 0x0c, 0x8d,
+ 0xce, 0xf9, 0x86, 0x00, 0x0a, 0xad, 0xfe, 0x3c, 0xd2, 0x14, 0xd4, 0xd2,
+ 0x18
+};
+unsigned int PK1_delete_auth_len = 1225;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/PK2.h b/components/service/uefi/smm_variable/test/service/auth_vectors/PK2.h
new file mode 100644
index 000000000..3ca9f1c9b
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/PK2.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char PK2_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0,
+ 0x7a, 0xa6, 0xe6, 0x9b, 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b,
+ 0xc7, 0xa8, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x50, 0x4b, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xcb, 0x94, 0x4f, 0x33, 0x47, 0xe3, 0xb3,
+ 0xd0, 0x34, 0x45, 0x48, 0xea, 0x6c, 0x66, 0x8d, 0xb0, 0x97, 0x41, 0xe8,
+ 0x81, 0x7f, 0xab, 0x83, 0xa5, 0x9f, 0xa6, 0x5d, 0x47, 0x9b, 0x60, 0x55,
+ 0xc3, 0x70, 0x2c, 0xf5, 0x96, 0x9f, 0xa8, 0xdb, 0xc0, 0xca, 0x63, 0x7c,
+ 0x34, 0xed, 0x14, 0x9e, 0xc0, 0xbe, 0xab, 0xe4, 0x3b, 0x73, 0xed, 0x62,
+ 0x24, 0xe8, 0x68, 0xa4, 0x14, 0x10, 0x50, 0x8f, 0x7f, 0x59, 0xad, 0xec,
+ 0x16, 0x60, 0xfe, 0x1f, 0x60, 0x3b, 0x9a, 0x7b, 0x7a, 0xc3, 0x3e, 0xf4,
+ 0xcf, 0x39, 0x27, 0x70, 0xb9, 0xd9, 0x0a, 0x40, 0xc7, 0x7f, 0x41, 0x80,
+ 0xd3, 0xe0, 0x22, 0x15, 0x1a, 0x91, 0x0e, 0x4a, 0xa7, 0x52, 0x33, 0x72,
+ 0xf2, 0x46, 0x03, 0x42, 0x36, 0x85, 0x27, 0xf0, 0x2f, 0x9f, 0x56, 0xa4,
+ 0xd5, 0xdc, 0x00, 0xd5, 0x5e, 0xe5, 0x1a, 0x08, 0xae, 0xdc, 0x80, 0xb9,
+ 0xa4, 0xcf, 0x58, 0xf1, 0xd4, 0x38, 0x5f, 0xe1, 0xff, 0x81, 0x01, 0xff,
+ 0x17, 0x77, 0xe7, 0x4b, 0xee, 0x91, 0xaf, 0x3a, 0xf9, 0x73, 0xd9, 0x6f,
+ 0xe9, 0x22, 0x55, 0x15, 0x17, 0xa9, 0xc9, 0xde, 0xfc, 0x63, 0xfc, 0x84,
+ 0x96, 0xb7, 0xf8, 0x40, 0x63, 0x5f, 0x2c, 0x21, 0x20, 0x1e, 0x37, 0x14,
+ 0x1b, 0x4e, 0x76, 0xec, 0x3a, 0xcb, 0xd5, 0xdc, 0xef, 0x96, 0x37, 0x43,
+ 0x46, 0x4c, 0x2e, 0xf4, 0xcb, 0x58, 0x90, 0x91, 0x35, 0x6d, 0xb5, 0x58,
+ 0xb8, 0xb7, 0x74, 0x72, 0x80, 0x3f, 0xb7, 0xd0, 0x1b, 0xca, 0x47, 0x18,
+ 0xc9, 0x99, 0x4d, 0x74, 0x97, 0x57, 0xc4, 0x2f, 0x2e, 0x2a, 0xd0, 0x95,
+ 0xc2, 0x1e, 0x64, 0x8d, 0xbd, 0xd1, 0x7e, 0xf6, 0x6c, 0x44, 0x01, 0x1f,
+ 0x37, 0xc0, 0x67, 0x7a, 0x78, 0x47, 0x21, 0xb4, 0x0d, 0xc6, 0xab, 0x81,
+ 0x7e, 0x1c, 0x10, 0x5d, 0x01, 0x2e, 0xfe, 0x41, 0x93, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4,
+ 0xbb, 0x06, 0xa7, 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66,
+ 0x08, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4, 0xbb, 0x06, 0xa7,
+ 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66, 0x08, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3a,
+ 0xae, 0xa0, 0xfa, 0x34, 0x4a, 0x52, 0x24, 0x90, 0x3a, 0xba, 0x33, 0x61,
+ 0x0f, 0xc8, 0x6f, 0xbc, 0x72, 0xf8, 0xc3, 0x98, 0x04, 0xe1, 0xcb, 0xf2,
+ 0x82, 0xfd, 0x83, 0x59, 0x51, 0x23, 0x71, 0xf4, 0xce, 0xe9, 0x36, 0x4d,
+ 0x0a, 0xd3, 0x11, 0x6d, 0x51, 0xb7, 0xd1, 0x9f, 0x9b, 0x85, 0x5c, 0x25,
+ 0x11, 0x9c, 0x13, 0xf6, 0x33, 0xd8, 0xa4, 0x27, 0xef, 0x90, 0x56, 0x21,
+ 0xe3, 0x90, 0x10, 0x2b, 0x50, 0x46, 0x6e, 0x8a, 0x84, 0x3e, 0x30, 0x4c,
+ 0xc2, 0xdf, 0x81, 0x60, 0xdf, 0xb8, 0x06, 0xd8, 0x2f, 0xcf, 0x3f, 0xb8,
+ 0xbe, 0x04, 0xa4, 0xbb, 0xba, 0x65, 0x9f, 0x4e, 0xc4, 0x05, 0xbe, 0x9e,
+ 0xfe, 0xa9, 0x0c, 0x06, 0x81, 0xcc, 0xa4, 0x66, 0xb0, 0x14, 0x48, 0xc9,
+ 0x24, 0x88, 0xd8, 0xdc, 0xf2, 0x5c, 0xb5, 0x59, 0x66, 0x4f, 0xc6, 0xa4,
+ 0xa3, 0x96, 0xa8, 0x48, 0x3b, 0x43, 0xff, 0xe0, 0x10, 0x53, 0x79, 0x47,
+ 0x74, 0xe8, 0xbc, 0xa9, 0x4f, 0x8e, 0x1f, 0xfb, 0xf8, 0xad, 0x8d, 0x10,
+ 0x80, 0x8f, 0x80, 0xf8, 0x5b, 0x36, 0xff, 0x60, 0x0b, 0x3f, 0xb2, 0x2f,
+ 0x46, 0x27, 0x43, 0x00, 0x1a, 0x0d, 0xb8, 0x91, 0x4e, 0x84, 0xb1, 0x94,
+ 0xc2, 0xca, 0xd6, 0x36, 0x4d, 0xc6, 0xda, 0x53, 0x71, 0xcc, 0xc8, 0x8e,
+ 0x9c, 0xdb, 0x31, 0xbb, 0x93, 0x49, 0xa7, 0xf4, 0x0b, 0x19, 0xcb, 0xaa,
+ 0x2b, 0x0c, 0xf4, 0xc7, 0x59, 0x8a, 0xc6, 0x59, 0x0b, 0x1d, 0x2f, 0xc3,
+ 0xcf, 0x06, 0xcf, 0x2e, 0x6b, 0x15, 0x6f, 0xba, 0xd1, 0xfa, 0x7d, 0x7f,
+ 0xaa, 0x99, 0x09, 0x63, 0xa8, 0xdd, 0x6c, 0xdb, 0x6a, 0x5e, 0x00, 0x5e,
+ 0x89, 0x11, 0xe3, 0xbd, 0xf6, 0xcb, 0x13, 0x89, 0x6a, 0xb8, 0x7e, 0x89,
+ 0xbc, 0xa5, 0xec, 0x68, 0x85, 0xf0, 0xaa, 0x05, 0x91, 0xc1, 0x79, 0xa1,
+ 0x1c, 0x9d, 0x32, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x31, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0, 0x7a, 0xa6, 0xe6, 0x9b,
+ 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b, 0xc7, 0xa8, 0x37, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xb8, 0xf2, 0x58,
+ 0x9f, 0x1b, 0x92, 0x17, 0x4f, 0x47, 0x0e, 0x55, 0x76, 0xdf, 0x6d, 0xdd,
+ 0x45, 0xba, 0x59, 0x0f, 0x60, 0x33, 0xee, 0x5a, 0x79, 0x5d, 0x52, 0x4b,
+ 0xcf, 0xd2, 0x37, 0x3c, 0x5d, 0xfd, 0x05, 0x16, 0x3d, 0xc7, 0x71, 0x15,
+ 0xde, 0xa9, 0x87, 0x67, 0x31, 0xef, 0x9a, 0xea, 0xce, 0x3f, 0x15, 0xc2,
+ 0x5c, 0xd3, 0xd2, 0x95, 0x63, 0xb5, 0xfe, 0x61, 0xd6, 0x53, 0x9f, 0x16,
+ 0xee, 0x28, 0xf1, 0xbc, 0xe9, 0x68, 0xc4, 0x3e, 0x72, 0x55, 0x2b, 0x8b,
+ 0x14, 0x86, 0x2f, 0x5f, 0x43, 0xda, 0x2b, 0x9b, 0x1b, 0x8e, 0x62, 0x33,
+ 0x7a, 0x7c, 0x3a, 0x00, 0x60, 0x7a, 0x25, 0x8b, 0x0e, 0x52, 0x09, 0x5a,
+ 0x9e, 0x65, 0x45, 0x2d, 0xd8, 0xb1, 0xae, 0x53, 0xc8, 0xdb, 0x39, 0xd9,
+ 0xe3, 0x3e, 0xa5, 0xb6, 0x9e, 0xa1, 0xdb, 0x8e, 0xc8, 0x7b, 0x27, 0x47,
+ 0xe5, 0x4a, 0x15, 0x57, 0x1b, 0x6d, 0xa3, 0xbb, 0x32, 0x66, 0xb7, 0x35,
+ 0x14, 0x27, 0xb2, 0xa3, 0x8d, 0xad, 0xb2, 0xe9, 0x1b, 0x79, 0x8a, 0x88,
+ 0xb6, 0x63, 0x9a, 0xa4, 0x59, 0xac, 0xa7, 0xe1, 0x6b, 0x4b, 0xb0, 0x18,
+ 0x79, 0xca, 0x3d, 0x9b, 0x90, 0x3d, 0x7c, 0x3a, 0xa5, 0x4c, 0xa8, 0x5c,
+ 0x32, 0xae, 0xad, 0x8b, 0xe9, 0x65, 0x06, 0x1b, 0x3a, 0xa5, 0xaa, 0x5c,
+ 0x3f, 0x3c, 0xb5, 0x05, 0x23, 0x8e, 0xae, 0x86, 0xdf, 0x84, 0x11, 0xf2,
+ 0x3f, 0xee, 0xa9, 0xd6, 0xd1, 0x07, 0x01, 0xd9, 0x8c, 0xe2, 0x0a, 0xbd,
+ 0x7b, 0x56, 0x5d, 0x10, 0xd2, 0x37, 0x53, 0x27, 0xf9, 0xbf, 0xcd, 0xfa,
+ 0x8d, 0x13, 0x30, 0x0b, 0xd8, 0x4d, 0x58, 0xee, 0x00, 0xd0, 0x2e, 0x0d,
+ 0x6a, 0xee, 0x8f, 0x1b, 0xcd, 0x04, 0x20, 0x74, 0xf6, 0x5d, 0x88, 0xaf,
+ 0xd8, 0x7b, 0xf2, 0x8a, 0xd6, 0x95, 0xa6, 0x4a, 0xc9, 0x61, 0xf2, 0xac,
+ 0x8e, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab,
+ 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03,
+ 0x07, 0x30, 0x82, 0x01, 0xef, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+ 0x54, 0xb4, 0x06, 0x14, 0xf0, 0x9e, 0x6a, 0xc1, 0xcf, 0x44, 0x44, 0xef,
+ 0x02, 0xf5, 0x79, 0x50, 0xf9, 0xaf, 0xf7, 0xe1, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x32, 0x30, 0x1e, 0x17, 0x0d,
+ 0x32, 0x34, 0x30, 0x31, 0x32, 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38,
+ 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32,
+ 0x30, 0x30, 0x38, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+ 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc1, 0x98,
+ 0xcb, 0x8b, 0xd4, 0x05, 0x9b, 0x8d, 0x45, 0x0d, 0xed, 0xe5, 0x32, 0x38,
+ 0x51, 0x41, 0xb1, 0xc6, 0x46, 0x30, 0x8d, 0xdf, 0x7d, 0xb3, 0xf9, 0x2f,
+ 0x4b, 0x87, 0x55, 0xcc, 0xb0, 0x10, 0xa0, 0xbd, 0x43, 0x9c, 0x09, 0x1e,
+ 0x7b, 0xa8, 0x50, 0x24, 0x87, 0x39, 0x8f, 0x3e, 0xb9, 0x33, 0x63, 0x3b,
+ 0xd3, 0x8a, 0x08, 0x1b, 0x8f, 0xee, 0x11, 0x5b, 0x2b, 0x8a, 0xc2, 0xe1,
+ 0x1e, 0x20, 0xf8, 0x41, 0x84, 0xc3, 0xea, 0x30, 0xaf, 0x36, 0x35, 0x6d,
+ 0xfe, 0x78, 0x66, 0x32, 0xdf, 0xe4, 0x13, 0xaa, 0x3a, 0xe7, 0x78, 0xc0,
+ 0x54, 0xc8, 0x8a, 0x05, 0xa3, 0x4a, 0x37, 0xc8, 0x09, 0xa8, 0x33, 0x5c,
+ 0xb7, 0xa5, 0x6c, 0x61, 0x70, 0x36, 0x47, 0xae, 0xc9, 0xaf, 0xcb, 0x01,
+ 0x85, 0x1e, 0x1f, 0x23, 0x9d, 0x1c, 0xc7, 0x42, 0xf0, 0x34, 0xe9, 0xb2,
+ 0x73, 0xa0, 0x74, 0x2a, 0x87, 0xc2, 0xdb, 0xef, 0x3a, 0xa3, 0xca, 0x20,
+ 0x42, 0xec, 0xd3, 0x62, 0x47, 0x79, 0x74, 0x7c, 0xa2, 0x72, 0x37, 0x11,
+ 0x99, 0xff, 0x07, 0x28, 0x5e, 0xc7, 0x25, 0x08, 0x69, 0xa0, 0x66, 0x95,
+ 0x8b, 0x0f, 0x89, 0x09, 0x4c, 0x99, 0x7d, 0x4f, 0xd5, 0x8c, 0xe2, 0xc6,
+ 0x54, 0xa4, 0x7e, 0xd2, 0xc8, 0x63, 0x2a, 0x6f, 0xe1, 0x86, 0x44, 0x27,
+ 0x16, 0x29, 0x06, 0x1f, 0x1d, 0x73, 0xfc, 0x9f, 0x7e, 0xf3, 0xbb, 0xae,
+ 0xb1, 0x77, 0x54, 0x2f, 0x62, 0xd2, 0x79, 0xd2, 0x38, 0x6d, 0x60, 0x68,
+ 0x3c, 0xbe, 0xae, 0x71, 0xb2, 0x7c, 0x06, 0x45, 0x6f, 0x5e, 0x5a, 0x44,
+ 0x36, 0x4f, 0xf9, 0x5d, 0x4e, 0xe7, 0xaf, 0xde, 0x54, 0x3a, 0x0d, 0xb7,
+ 0x19, 0x96, 0xad, 0x5e, 0x99, 0xac, 0x80, 0x24, 0x2d, 0x74, 0x1f, 0x35,
+ 0xf9, 0xed, 0x30, 0x1e, 0xdc, 0x8b, 0x32, 0xcd, 0x25, 0xe4, 0x28, 0x27,
+ 0x03, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30,
+ 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x87, 0x5a,
+ 0x48, 0x88, 0x29, 0xf1, 0x9c, 0xfe, 0xfa, 0xde, 0xd7, 0xd8, 0xd9, 0x55,
+ 0xd7, 0x22, 0x5d, 0xc2, 0x7f, 0x35, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x87, 0x5a, 0x48, 0x88, 0x29,
+ 0xf1, 0x9c, 0xfe, 0xfa, 0xde, 0xd7, 0xd8, 0xd9, 0x55, 0xd7, 0x22, 0x5d,
+ 0xc2, 0x7f, 0x35, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+ 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x01, 0x00, 0xac, 0xa0, 0x15, 0xab, 0xce, 0x98, 0xaa, 0x61,
+ 0x6d, 0x3c, 0x84, 0xfa, 0x10, 0xed, 0xa8, 0x59, 0x32, 0x00, 0x37, 0x80,
+ 0x96, 0xb8, 0x51, 0x0a, 0xd8, 0xae, 0x74, 0x4e, 0x47, 0x8a, 0x8d, 0x1b,
+ 0xc6, 0xeb, 0x06, 0x58, 0xcd, 0x02, 0x73, 0xf7, 0x33, 0x6c, 0x5c, 0x7a,
+ 0x69, 0xd5, 0x65, 0xf3, 0x85, 0xe8, 0x3f, 0x91, 0x3a, 0xd4, 0x7c, 0x36,
+ 0x9a, 0xa8, 0xbb, 0xec, 0x74, 0x41, 0x7d, 0xd3, 0x40, 0xe4, 0x78, 0x2d,
+ 0x36, 0x29, 0xfa, 0x58, 0x2e, 0xbc, 0x56, 0x40, 0x44, 0x32, 0xc6, 0x51,
+ 0x85, 0xc2, 0x24, 0xb0, 0xaa, 0x0b, 0x3c, 0x06, 0x95, 0xb3, 0x6d, 0x68,
+ 0x91, 0x99, 0x86, 0xe9, 0xb2, 0xba, 0x7d, 0x28, 0xdd, 0x2d, 0x67, 0x3c,
+ 0x8c, 0x85, 0xaa, 0x6c, 0x94, 0xd4, 0xae, 0xfd, 0x6a, 0xaa, 0xf9, 0x53,
+ 0x04, 0xe6, 0x13, 0x4a, 0x7b, 0x2c, 0x94, 0x10, 0x41, 0x74, 0x2a, 0x41,
+ 0xdd, 0x10, 0xfc, 0x86, 0x23, 0x62, 0xf2, 0x9a, 0xb6, 0x41, 0xc5, 0xbd,
+ 0x4f, 0xaa, 0xd5, 0xcc, 0x74, 0x9c, 0xf7, 0x3b, 0x31, 0x9a, 0xda, 0xf2,
+ 0x20, 0x5d, 0x8a, 0x1e, 0xe3, 0xff, 0xd8, 0x7e, 0xa3, 0x2e, 0x8f, 0x5a,
+ 0x30, 0x68, 0x85, 0xd6, 0x9f, 0xf1, 0xbd, 0x6a, 0x49, 0x64, 0x93, 0x2d,
+ 0xb0, 0x5e, 0x68, 0x44, 0xb6, 0xfe, 0x64, 0x19, 0x75, 0x72, 0x49, 0x14,
+ 0x32, 0xff, 0x0a, 0x2b, 0x15, 0x3f, 0xb4, 0x98, 0x69, 0xee, 0x1e, 0xbf,
+ 0x0e, 0x14, 0x18, 0xe4, 0xc7, 0x78, 0x6d, 0x39, 0x5a, 0xfc, 0x41, 0x8b,
+ 0x23, 0x42, 0xf2, 0x9f, 0x7d, 0x18, 0xee, 0x23, 0x6e, 0x67, 0x9f, 0xe9,
+ 0x38, 0x51, 0x14, 0x67, 0xca, 0x5c, 0x75, 0xc9, 0xf3, 0x8c, 0xaa, 0x68,
+ 0x2a, 0x28, 0xd5, 0xa4, 0x07, 0xbb, 0xe9, 0x5b, 0xf2, 0xde, 0x74, 0x13,
+ 0x08, 0x6c, 0x8f, 0x31, 0x3a, 0x52, 0x08, 0x56
+};
+unsigned int PK2_auth_len = 2048;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/PK2_delete.h b/components/service/uefi/smm_variable/test/service/auth_vectors/PK2_delete.h
new file mode 100644
index 000000000..ca33bb520
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/PK2_delete.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char PK2_delete_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x54, 0xb4, 0x06, 0x14, 0xf0,
+ 0x9e, 0x6a, 0xc1, 0xcf, 0x44, 0x44, 0xef, 0x02, 0xf5, 0x79, 0x50, 0xf9,
+ 0xaf, 0xf7, 0xe1, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x50, 0x4b, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x32, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xc1, 0x98, 0xcb, 0x8b, 0xd4, 0x05, 0x9b,
+ 0x8d, 0x45, 0x0d, 0xed, 0xe5, 0x32, 0x38, 0x51, 0x41, 0xb1, 0xc6, 0x46,
+ 0x30, 0x8d, 0xdf, 0x7d, 0xb3, 0xf9, 0x2f, 0x4b, 0x87, 0x55, 0xcc, 0xb0,
+ 0x10, 0xa0, 0xbd, 0x43, 0x9c, 0x09, 0x1e, 0x7b, 0xa8, 0x50, 0x24, 0x87,
+ 0x39, 0x8f, 0x3e, 0xb9, 0x33, 0x63, 0x3b, 0xd3, 0x8a, 0x08, 0x1b, 0x8f,
+ 0xee, 0x11, 0x5b, 0x2b, 0x8a, 0xc2, 0xe1, 0x1e, 0x20, 0xf8, 0x41, 0x84,
+ 0xc3, 0xea, 0x30, 0xaf, 0x36, 0x35, 0x6d, 0xfe, 0x78, 0x66, 0x32, 0xdf,
+ 0xe4, 0x13, 0xaa, 0x3a, 0xe7, 0x78, 0xc0, 0x54, 0xc8, 0x8a, 0x05, 0xa3,
+ 0x4a, 0x37, 0xc8, 0x09, 0xa8, 0x33, 0x5c, 0xb7, 0xa5, 0x6c, 0x61, 0x70,
+ 0x36, 0x47, 0xae, 0xc9, 0xaf, 0xcb, 0x01, 0x85, 0x1e, 0x1f, 0x23, 0x9d,
+ 0x1c, 0xc7, 0x42, 0xf0, 0x34, 0xe9, 0xb2, 0x73, 0xa0, 0x74, 0x2a, 0x87,
+ 0xc2, 0xdb, 0xef, 0x3a, 0xa3, 0xca, 0x20, 0x42, 0xec, 0xd3, 0x62, 0x47,
+ 0x79, 0x74, 0x7c, 0xa2, 0x72, 0x37, 0x11, 0x99, 0xff, 0x07, 0x28, 0x5e,
+ 0xc7, 0x25, 0x08, 0x69, 0xa0, 0x66, 0x95, 0x8b, 0x0f, 0x89, 0x09, 0x4c,
+ 0x99, 0x7d, 0x4f, 0xd5, 0x8c, 0xe2, 0xc6, 0x54, 0xa4, 0x7e, 0xd2, 0xc8,
+ 0x63, 0x2a, 0x6f, 0xe1, 0x86, 0x44, 0x27, 0x16, 0x29, 0x06, 0x1f, 0x1d,
+ 0x73, 0xfc, 0x9f, 0x7e, 0xf3, 0xbb, 0xae, 0xb1, 0x77, 0x54, 0x2f, 0x62,
+ 0xd2, 0x79, 0xd2, 0x38, 0x6d, 0x60, 0x68, 0x3c, 0xbe, 0xae, 0x71, 0xb2,
+ 0x7c, 0x06, 0x45, 0x6f, 0x5e, 0x5a, 0x44, 0x36, 0x4f, 0xf9, 0x5d, 0x4e,
+ 0xe7, 0xaf, 0xde, 0x54, 0x3a, 0x0d, 0xb7, 0x19, 0x96, 0xad, 0x5e, 0x99,
+ 0xac, 0x80, 0x24, 0x2d, 0x74, 0x1f, 0x35, 0xf9, 0xed, 0x30, 0x1e, 0xdc,
+ 0x8b, 0x32, 0xcd, 0x25, 0xe4, 0x28, 0x27, 0x03, 0x05, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x87, 0x5a, 0x48, 0x88, 0x29, 0xf1, 0x9c,
+ 0xfe, 0xfa, 0xde, 0xd7, 0xd8, 0xd9, 0x55, 0xd7, 0x22, 0x5d, 0xc2, 0x7f,
+ 0x35, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x87, 0x5a, 0x48, 0x88, 0x29, 0xf1, 0x9c, 0xfe, 0xfa, 0xde,
+ 0xd7, 0xd8, 0xd9, 0x55, 0xd7, 0x22, 0x5d, 0xc2, 0x7f, 0x35, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xac,
+ 0xa0, 0x15, 0xab, 0xce, 0x98, 0xaa, 0x61, 0x6d, 0x3c, 0x84, 0xfa, 0x10,
+ 0xed, 0xa8, 0x59, 0x32, 0x00, 0x37, 0x80, 0x96, 0xb8, 0x51, 0x0a, 0xd8,
+ 0xae, 0x74, 0x4e, 0x47, 0x8a, 0x8d, 0x1b, 0xc6, 0xeb, 0x06, 0x58, 0xcd,
+ 0x02, 0x73, 0xf7, 0x33, 0x6c, 0x5c, 0x7a, 0x69, 0xd5, 0x65, 0xf3, 0x85,
+ 0xe8, 0x3f, 0x91, 0x3a, 0xd4, 0x7c, 0x36, 0x9a, 0xa8, 0xbb, 0xec, 0x74,
+ 0x41, 0x7d, 0xd3, 0x40, 0xe4, 0x78, 0x2d, 0x36, 0x29, 0xfa, 0x58, 0x2e,
+ 0xbc, 0x56, 0x40, 0x44, 0x32, 0xc6, 0x51, 0x85, 0xc2, 0x24, 0xb0, 0xaa,
+ 0x0b, 0x3c, 0x06, 0x95, 0xb3, 0x6d, 0x68, 0x91, 0x99, 0x86, 0xe9, 0xb2,
+ 0xba, 0x7d, 0x28, 0xdd, 0x2d, 0x67, 0x3c, 0x8c, 0x85, 0xaa, 0x6c, 0x94,
+ 0xd4, 0xae, 0xfd, 0x6a, 0xaa, 0xf9, 0x53, 0x04, 0xe6, 0x13, 0x4a, 0x7b,
+ 0x2c, 0x94, 0x10, 0x41, 0x74, 0x2a, 0x41, 0xdd, 0x10, 0xfc, 0x86, 0x23,
+ 0x62, 0xf2, 0x9a, 0xb6, 0x41, 0xc5, 0xbd, 0x4f, 0xaa, 0xd5, 0xcc, 0x74,
+ 0x9c, 0xf7, 0x3b, 0x31, 0x9a, 0xda, 0xf2, 0x20, 0x5d, 0x8a, 0x1e, 0xe3,
+ 0xff, 0xd8, 0x7e, 0xa3, 0x2e, 0x8f, 0x5a, 0x30, 0x68, 0x85, 0xd6, 0x9f,
+ 0xf1, 0xbd, 0x6a, 0x49, 0x64, 0x93, 0x2d, 0xb0, 0x5e, 0x68, 0x44, 0xb6,
+ 0xfe, 0x64, 0x19, 0x75, 0x72, 0x49, 0x14, 0x32, 0xff, 0x0a, 0x2b, 0x15,
+ 0x3f, 0xb4, 0x98, 0x69, 0xee, 0x1e, 0xbf, 0x0e, 0x14, 0x18, 0xe4, 0xc7,
+ 0x78, 0x6d, 0x39, 0x5a, 0xfc, 0x41, 0x8b, 0x23, 0x42, 0xf2, 0x9f, 0x7d,
+ 0x18, 0xee, 0x23, 0x6e, 0x67, 0x9f, 0xe9, 0x38, 0x51, 0x14, 0x67, 0xca,
+ 0x5c, 0x75, 0xc9, 0xf3, 0x8c, 0xaa, 0x68, 0x2a, 0x28, 0xd5, 0xa4, 0x07,
+ 0xbb, 0xe9, 0x5b, 0xf2, 0xde, 0x74, 0x13, 0x08, 0x6c, 0x8f, 0x31, 0x3a,
+ 0x52, 0x08, 0x56, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x32, 0x02, 0x14, 0x54, 0xb4, 0x06, 0x14, 0xf0, 0x9e, 0x6a, 0xc1, 0xcf,
+ 0x44, 0x44, 0xef, 0x02, 0xf5, 0x79, 0x50, 0xf9, 0xaf, 0xf7, 0xe1, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x2a, 0xad, 0x1c,
+ 0xf0, 0x25, 0xb8, 0x5f, 0x04, 0xc8, 0xef, 0x99, 0x03, 0xce, 0x68, 0x1c,
+ 0x1e, 0x78, 0x60, 0x44, 0x1f, 0x4a, 0x94, 0xe8, 0xc5, 0x12, 0x38, 0x0d,
+ 0x2d, 0x21, 0x9d, 0xd8, 0x2f, 0x98, 0x58, 0x4a, 0xf4, 0x1f, 0x92, 0xf8,
+ 0x9b, 0x7d, 0x7a, 0x7e, 0x43, 0xab, 0xaf, 0x6e, 0xa2, 0x59, 0xb4, 0xa0,
+ 0xff, 0x91, 0xba, 0x13, 0x8a, 0x6d, 0x72, 0xcc, 0x28, 0x0d, 0xab, 0xd4,
+ 0x07, 0xf1, 0xd4, 0xa5, 0xbc, 0x0f, 0x68, 0x3d, 0x2c, 0x87, 0x95, 0xe8,
+ 0x4b, 0x2b, 0x55, 0x55, 0xda, 0xf8, 0x0c, 0xea, 0xfd, 0x99, 0x77, 0x5d,
+ 0xbc, 0xd4, 0xae, 0x2e, 0x64, 0xb2, 0x84, 0xcb, 0x92, 0x1c, 0x83, 0x18,
+ 0xc3, 0x25, 0x4d, 0x38, 0x62, 0x5b, 0x47, 0x19, 0x1f, 0x95, 0x83, 0x93,
+ 0x65, 0xf9, 0x2a, 0x5f, 0x1d, 0x6d, 0xf4, 0x1c, 0xeb, 0x7e, 0xcf, 0x4d,
+ 0xc8, 0xf1, 0x87, 0x32, 0xa1, 0x23, 0x62, 0xfd, 0x47, 0xb1, 0x6d, 0xe6,
+ 0x30, 0x9f, 0x39, 0x67, 0x5e, 0x9f, 0x4d, 0x4c, 0x8d, 0x97, 0x0c, 0xf2,
+ 0xda, 0xcb, 0xb1, 0xfa, 0x26, 0x44, 0x53, 0xa4, 0x3c, 0x5f, 0x1e, 0x49,
+ 0xf9, 0xaf, 0x88, 0x37, 0xd8, 0x48, 0x00, 0xc5, 0xbb, 0x37, 0xe3, 0x6b,
+ 0x6d, 0x32, 0x27, 0xc2, 0xc1, 0x14, 0x79, 0x02, 0x56, 0x46, 0xb4, 0x6b,
+ 0x69, 0xe6, 0x6d, 0x01, 0x31, 0xa7, 0xaa, 0xe6, 0xb7, 0x50, 0x23, 0xac,
+ 0x2c, 0x6c, 0xb2, 0x38, 0x81, 0x85, 0xfa, 0x51, 0x96, 0x3f, 0x3e, 0x7b,
+ 0xef, 0xaa, 0x35, 0x4a, 0x7a, 0xfc, 0x30, 0x7b, 0x3b, 0xf0, 0xf5, 0xa1,
+ 0x2d, 0x96, 0xdd, 0x13, 0x90, 0xc0, 0x3c, 0x41, 0xc0, 0x42, 0xdc, 0x5c,
+ 0xb1, 0x14, 0x35, 0x0e, 0xd0, 0xda, 0xa9, 0x1a, 0x75, 0x38, 0x77, 0x7f,
+ 0xa5, 0x71, 0x77, 0x7a, 0x42, 0xde, 0x64, 0x71, 0x68, 0x2e, 0x78, 0xeb,
+ 0x4a
+};
+unsigned int PK2_delete_auth_len = 1225;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/PK3.h b/components/service/uefi/smm_variable/test/service/auth_vectors/PK3.h
new file mode 100644
index 000000000..5a0a39dd5
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/PK3.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char PK3_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x11, 0x90, 0xbd, 0xc1, 0x8a,
+ 0x36, 0x84, 0x80, 0x84, 0xa0, 0xe2, 0x8f, 0x57, 0xc9, 0x25, 0x01, 0xd7,
+ 0x71, 0x9f, 0x6f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x50, 0x4b, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x33, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xd4, 0x89, 0x82, 0x3f, 0x53, 0x8c, 0x94,
+ 0xba, 0xbf, 0xff, 0xfd, 0x18, 0x9b, 0xa0, 0x30, 0x7e, 0x56, 0xd7, 0xe1,
+ 0xdb, 0x77, 0x88, 0x35, 0xa8, 0x20, 0x69, 0xe2, 0x3a, 0xcf, 0x0b, 0x87,
+ 0xd0, 0x06, 0x39, 0x83, 0x46, 0x15, 0xe8, 0x36, 0xf1, 0xf5, 0x3e, 0x46,
+ 0xed, 0xa8, 0x8c, 0x11, 0x33, 0x9f, 0x72, 0xc0, 0x57, 0xd0, 0x06, 0x35,
+ 0x06, 0xc7, 0xd5, 0xdb, 0xeb, 0x3d, 0x12, 0xc4, 0xc2, 0x0c, 0x5e, 0x14,
+ 0xf4, 0x7c, 0x3a, 0xd8, 0x55, 0x37, 0xcd, 0x55, 0x2c, 0x37, 0x98, 0x2b,
+ 0xdb, 0x3b, 0xfe, 0x70, 0x06, 0x56, 0x64, 0x03, 0x64, 0x13, 0xd6, 0x73,
+ 0xf3, 0x93, 0x8b, 0xc3, 0x37, 0xa5, 0xb7, 0xa0, 0x40, 0xb6, 0x3d, 0x7e,
+ 0x79, 0x86, 0xc6, 0x33, 0x3c, 0x2a, 0x5a, 0x0f, 0x91, 0x91, 0xef, 0xdb,
+ 0xca, 0x47, 0x58, 0x83, 0xde, 0x22, 0x81, 0x8f, 0x19, 0x49, 0x6f, 0x3b,
+ 0xae, 0x06, 0xad, 0xda, 0xb6, 0xad, 0x04, 0x62, 0xe2, 0xb0, 0x14, 0xc4,
+ 0xb0, 0xc3, 0x7d, 0x2f, 0x48, 0x19, 0x75, 0xd0, 0xda, 0x81, 0x60, 0x0d,
+ 0x03, 0xbd, 0x1b, 0xfd, 0xb6, 0x10, 0x7b, 0x23, 0x4e, 0x91, 0xa6, 0xff,
+ 0xbd, 0xd5, 0xfe, 0xd7, 0x3f, 0x63, 0x53, 0x1f, 0x48, 0xe5, 0xc9, 0x6d,
+ 0x69, 0xcd, 0x0e, 0xde, 0x54, 0xe3, 0x42, 0xb6, 0xdc, 0x12, 0x2e, 0x0c,
+ 0xcf, 0x40, 0x58, 0x52, 0xef, 0xad, 0x8d, 0xf4, 0x52, 0x56, 0xda, 0x3b,
+ 0x47, 0xb1, 0x4c, 0xc6, 0xe1, 0x3a, 0x6f, 0x28, 0xe9, 0xf9, 0x10, 0x86,
+ 0x37, 0x24, 0x74, 0xe5, 0x03, 0xb1, 0x95, 0x71, 0xe4, 0xf4, 0xe5, 0xaa,
+ 0xb3, 0x88, 0x15, 0x20, 0x3c, 0xc8, 0x00, 0x2d, 0x04, 0x4a, 0x7e, 0x35,
+ 0x7c, 0x70, 0xb1, 0xa6, 0xad, 0x82, 0xa0, 0x77, 0xb5, 0x4d, 0xd4, 0x92,
+ 0x0c, 0x9a, 0xca, 0x8b, 0xdd, 0x75, 0x28, 0xae, 0x99, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0xae, 0xfa, 0xbf, 0x66, 0xb9, 0xc6, 0xf2,
+ 0x3b, 0x01, 0x7f, 0x52, 0x90, 0x41, 0x6d, 0x0e, 0x33, 0x51, 0x01, 0x7c,
+ 0x7e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0xae, 0xfa, 0xbf, 0x66, 0xb9, 0xc6, 0xf2, 0x3b, 0x01, 0x7f,
+ 0x52, 0x90, 0x41, 0x6d, 0x0e, 0x33, 0x51, 0x01, 0x7c, 0x7e, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xb8,
+ 0xdb, 0x9a, 0x38, 0x6e, 0xb1, 0x48, 0xe0, 0x5a, 0x9b, 0xd5, 0xec, 0x2e,
+ 0xe5, 0x8a, 0xb5, 0xc7, 0x4e, 0x9f, 0xe9, 0x8d, 0xde, 0x11, 0xc5, 0xe0,
+ 0x8a, 0x75, 0xe6, 0x04, 0x7e, 0xfa, 0xcb, 0x3e, 0xa2, 0xb8, 0x28, 0xf3,
+ 0xbc, 0xc5, 0xaf, 0x6d, 0x2a, 0x45, 0x34, 0x91, 0x62, 0xf5, 0xe1, 0x66,
+ 0x7f, 0x82, 0xd9, 0xac, 0xc4, 0x29, 0x36, 0xed, 0xcb, 0x8a, 0x97, 0x88,
+ 0x6c, 0x8f, 0xa1, 0x19, 0xbd, 0x04, 0xe1, 0x1c, 0x95, 0x7f, 0x45, 0xe3,
+ 0x8c, 0xda, 0x74, 0xa7, 0xd9, 0x4d, 0x41, 0x34, 0x96, 0x77, 0xe0, 0x68,
+ 0xd7, 0x7b, 0xff, 0x62, 0x1d, 0xa3, 0xaf, 0x12, 0xdc, 0x6a, 0xf1, 0xaf,
+ 0x09, 0xa2, 0xc6, 0x72, 0xa4, 0xbb, 0xcf, 0xd4, 0x96, 0xae, 0x41, 0xfc,
+ 0x77, 0x56, 0xe7, 0xe0, 0x8e, 0x0a, 0x80, 0xd5, 0xc1, 0xb4, 0xfd, 0xa9,
+ 0xf4, 0x8d, 0xc8, 0x26, 0xf8, 0x21, 0x0b, 0x8c, 0xc3, 0x6a, 0x75, 0x46,
+ 0xf2, 0x3f, 0x5c, 0x42, 0xd6, 0xe4, 0x98, 0x73, 0x72, 0x9a, 0x34, 0x71,
+ 0x4f, 0xa2, 0x97, 0x2e, 0x63, 0x1f, 0x38, 0x25, 0x1c, 0xb8, 0xf8, 0xec,
+ 0xc0, 0x60, 0x14, 0x9a, 0x9d, 0x91, 0xc0, 0x0e, 0xbb, 0x23, 0xfc, 0x25,
+ 0x8b, 0x01, 0x20, 0x2d, 0x30, 0x0f, 0x25, 0xa7, 0x0a, 0xbe, 0x91, 0xf3,
+ 0xb5, 0x15, 0x77, 0x07, 0x59, 0x4a, 0x3a, 0xc7, 0x1b, 0xb9, 0xc9, 0x48,
+ 0xa4, 0xfe, 0x05, 0xe2, 0x50, 0x89, 0x26, 0xd8, 0x13, 0xe1, 0xd2, 0xe4,
+ 0x5d, 0x34, 0xa3, 0x8f, 0x99, 0x00, 0xd0, 0x11, 0x13, 0x97, 0x4c, 0x41,
+ 0x2d, 0x63, 0xdf, 0xb6, 0xa6, 0xc1, 0xb5, 0x9f, 0x08, 0xda, 0x44, 0xd1,
+ 0x80, 0x1d, 0xe3, 0x82, 0x12, 0x5e, 0xa8, 0x63, 0x8f, 0x74, 0xf2, 0xab,
+ 0xbb, 0xf6, 0xca, 0x2a, 0x51, 0xa2, 0xc2, 0xcc, 0x85, 0x37, 0x85, 0x97,
+ 0x1a, 0x4c, 0x3e, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x33, 0x02, 0x14, 0x11, 0x90, 0xbd, 0xc1, 0x8a, 0x36, 0x84, 0x80, 0x84,
+ 0xa0, 0xe2, 0x8f, 0x57, 0xc9, 0x25, 0x01, 0xd7, 0x71, 0x9f, 0x6f, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x00, 0x8c, 0x4d,
+ 0xfa, 0xc3, 0xc1, 0x69, 0x2f, 0x8f, 0x25, 0x46, 0x68, 0xf4, 0x57, 0x99,
+ 0xd3, 0xd0, 0xb9, 0x01, 0xc0, 0xec, 0xc3, 0xe7, 0x22, 0x72, 0xeb, 0xab,
+ 0x72, 0xc3, 0x5f, 0x70, 0x9b, 0x83, 0xb7, 0xf0, 0x7e, 0x8e, 0x42, 0x35,
+ 0x8d, 0xf9, 0x32, 0xe0, 0x07, 0x38, 0x9d, 0x0a, 0x0f, 0x64, 0xaf, 0x45,
+ 0xc6, 0xfe, 0x2d, 0x6a, 0x3a, 0xe5, 0x2e, 0xd4, 0xae, 0x9b, 0x7d, 0x05,
+ 0x73, 0x3b, 0xa0, 0xbb, 0x64, 0x91, 0xd9, 0x44, 0x9d, 0xdb, 0x05, 0xec,
+ 0xca, 0x2c, 0x25, 0xc3, 0xa1, 0xc3, 0x89, 0x40, 0x03, 0x53, 0x78, 0x42,
+ 0x55, 0x14, 0x30, 0xba, 0xeb, 0xa3, 0x4b, 0xc4, 0x53, 0xc9, 0x20, 0xd2,
+ 0x41, 0x89, 0xa9, 0x00, 0x48, 0xac, 0x90, 0xea, 0xef, 0x31, 0x9a, 0x79,
+ 0xd0, 0x9d, 0x20, 0xdf, 0x80, 0x0f, 0x2c, 0xd1, 0x13, 0x5e, 0x7a, 0xc4,
+ 0x08, 0x07, 0xd6, 0xe7, 0x49, 0xd3, 0x05, 0x95, 0xb5, 0xbd, 0x19, 0xfb,
+ 0x97, 0x1b, 0xd6, 0xd4, 0x2f, 0xfb, 0x3c, 0xbb, 0xa9, 0xc4, 0xd3, 0x6f,
+ 0xda, 0x40, 0x02, 0x39, 0xad, 0x90, 0xb7, 0xa2, 0x36, 0xe7, 0x72, 0xf7,
+ 0xb6, 0xdf, 0x2f, 0x68, 0x02, 0xb0, 0x66, 0x37, 0x6e, 0x4f, 0xe3, 0x5b,
+ 0x5f, 0x4b, 0x17, 0x1f, 0x36, 0x02, 0x81, 0x5a, 0x32, 0x41, 0x0d, 0xd1,
+ 0xbb, 0x02, 0xcb, 0x46, 0x95, 0xdf, 0x92, 0xde, 0x23, 0x28, 0x71, 0x77,
+ 0x1c, 0xf1, 0x77, 0x2e, 0x1b, 0xe4, 0x62, 0x00, 0x78, 0x28, 0x94, 0x2b,
+ 0x06, 0x46, 0x6e, 0x29, 0x09, 0x78, 0x30, 0xa5, 0xb9, 0x4e, 0x70, 0xcb,
+ 0x1b, 0x01, 0xd8, 0x6c, 0x6b, 0xdc, 0xcf, 0xd4, 0xc3, 0x03, 0xe0, 0xd5,
+ 0x4e, 0x6a, 0x8d, 0x4b, 0x62, 0xe5, 0x42, 0xf2, 0x62, 0x30, 0x1f, 0x53,
+ 0xd8, 0x8e, 0x57, 0xa8, 0xef, 0xfc, 0x87, 0x31, 0x08, 0xfd, 0xc6, 0xf0,
+ 0x3c, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab,
+ 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03,
+ 0x07, 0x30, 0x82, 0x01, 0xef, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+ 0x11, 0x90, 0xbd, 0xc1, 0x8a, 0x36, 0x84, 0x80, 0x84, 0xa0, 0xe2, 0x8f,
+ 0x57, 0xc9, 0x25, 0x01, 0xd7, 0x71, 0x9f, 0x6f, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x33, 0x30, 0x1e, 0x17, 0x0d,
+ 0x32, 0x34, 0x30, 0x31, 0x32, 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38,
+ 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32,
+ 0x30, 0x30, 0x38, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+ 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd4, 0x89,
+ 0x82, 0x3f, 0x53, 0x8c, 0x94, 0xba, 0xbf, 0xff, 0xfd, 0x18, 0x9b, 0xa0,
+ 0x30, 0x7e, 0x56, 0xd7, 0xe1, 0xdb, 0x77, 0x88, 0x35, 0xa8, 0x20, 0x69,
+ 0xe2, 0x3a, 0xcf, 0x0b, 0x87, 0xd0, 0x06, 0x39, 0x83, 0x46, 0x15, 0xe8,
+ 0x36, 0xf1, 0xf5, 0x3e, 0x46, 0xed, 0xa8, 0x8c, 0x11, 0x33, 0x9f, 0x72,
+ 0xc0, 0x57, 0xd0, 0x06, 0x35, 0x06, 0xc7, 0xd5, 0xdb, 0xeb, 0x3d, 0x12,
+ 0xc4, 0xc2, 0x0c, 0x5e, 0x14, 0xf4, 0x7c, 0x3a, 0xd8, 0x55, 0x37, 0xcd,
+ 0x55, 0x2c, 0x37, 0x98, 0x2b, 0xdb, 0x3b, 0xfe, 0x70, 0x06, 0x56, 0x64,
+ 0x03, 0x64, 0x13, 0xd6, 0x73, 0xf3, 0x93, 0x8b, 0xc3, 0x37, 0xa5, 0xb7,
+ 0xa0, 0x40, 0xb6, 0x3d, 0x7e, 0x79, 0x86, 0xc6, 0x33, 0x3c, 0x2a, 0x5a,
+ 0x0f, 0x91, 0x91, 0xef, 0xdb, 0xca, 0x47, 0x58, 0x83, 0xde, 0x22, 0x81,
+ 0x8f, 0x19, 0x49, 0x6f, 0x3b, 0xae, 0x06, 0xad, 0xda, 0xb6, 0xad, 0x04,
+ 0x62, 0xe2, 0xb0, 0x14, 0xc4, 0xb0, 0xc3, 0x7d, 0x2f, 0x48, 0x19, 0x75,
+ 0xd0, 0xda, 0x81, 0x60, 0x0d, 0x03, 0xbd, 0x1b, 0xfd, 0xb6, 0x10, 0x7b,
+ 0x23, 0x4e, 0x91, 0xa6, 0xff, 0xbd, 0xd5, 0xfe, 0xd7, 0x3f, 0x63, 0x53,
+ 0x1f, 0x48, 0xe5, 0xc9, 0x6d, 0x69, 0xcd, 0x0e, 0xde, 0x54, 0xe3, 0x42,
+ 0xb6, 0xdc, 0x12, 0x2e, 0x0c, 0xcf, 0x40, 0x58, 0x52, 0xef, 0xad, 0x8d,
+ 0xf4, 0x52, 0x56, 0xda, 0x3b, 0x47, 0xb1, 0x4c, 0xc6, 0xe1, 0x3a, 0x6f,
+ 0x28, 0xe9, 0xf9, 0x10, 0x86, 0x37, 0x24, 0x74, 0xe5, 0x03, 0xb1, 0x95,
+ 0x71, 0xe4, 0xf4, 0xe5, 0xaa, 0xb3, 0x88, 0x15, 0x20, 0x3c, 0xc8, 0x00,
+ 0x2d, 0x04, 0x4a, 0x7e, 0x35, 0x7c, 0x70, 0xb1, 0xa6, 0xad, 0x82, 0xa0,
+ 0x77, 0xb5, 0x4d, 0xd4, 0x92, 0x0c, 0x9a, 0xca, 0x8b, 0xdd, 0x75, 0x28,
+ 0xae, 0x99, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30,
+ 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xae, 0xfa,
+ 0xbf, 0x66, 0xb9, 0xc6, 0xf2, 0x3b, 0x01, 0x7f, 0x52, 0x90, 0x41, 0x6d,
+ 0x0e, 0x33, 0x51, 0x01, 0x7c, 0x7e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xae, 0xfa, 0xbf, 0x66, 0xb9,
+ 0xc6, 0xf2, 0x3b, 0x01, 0x7f, 0x52, 0x90, 0x41, 0x6d, 0x0e, 0x33, 0x51,
+ 0x01, 0x7c, 0x7e, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+ 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x01, 0x00, 0xb8, 0xdb, 0x9a, 0x38, 0x6e, 0xb1, 0x48, 0xe0,
+ 0x5a, 0x9b, 0xd5, 0xec, 0x2e, 0xe5, 0x8a, 0xb5, 0xc7, 0x4e, 0x9f, 0xe9,
+ 0x8d, 0xde, 0x11, 0xc5, 0xe0, 0x8a, 0x75, 0xe6, 0x04, 0x7e, 0xfa, 0xcb,
+ 0x3e, 0xa2, 0xb8, 0x28, 0xf3, 0xbc, 0xc5, 0xaf, 0x6d, 0x2a, 0x45, 0x34,
+ 0x91, 0x62, 0xf5, 0xe1, 0x66, 0x7f, 0x82, 0xd9, 0xac, 0xc4, 0x29, 0x36,
+ 0xed, 0xcb, 0x8a, 0x97, 0x88, 0x6c, 0x8f, 0xa1, 0x19, 0xbd, 0x04, 0xe1,
+ 0x1c, 0x95, 0x7f, 0x45, 0xe3, 0x8c, 0xda, 0x74, 0xa7, 0xd9, 0x4d, 0x41,
+ 0x34, 0x96, 0x77, 0xe0, 0x68, 0xd7, 0x7b, 0xff, 0x62, 0x1d, 0xa3, 0xaf,
+ 0x12, 0xdc, 0x6a, 0xf1, 0xaf, 0x09, 0xa2, 0xc6, 0x72, 0xa4, 0xbb, 0xcf,
+ 0xd4, 0x96, 0xae, 0x41, 0xfc, 0x77, 0x56, 0xe7, 0xe0, 0x8e, 0x0a, 0x80,
+ 0xd5, 0xc1, 0xb4, 0xfd, 0xa9, 0xf4, 0x8d, 0xc8, 0x26, 0xf8, 0x21, 0x0b,
+ 0x8c, 0xc3, 0x6a, 0x75, 0x46, 0xf2, 0x3f, 0x5c, 0x42, 0xd6, 0xe4, 0x98,
+ 0x73, 0x72, 0x9a, 0x34, 0x71, 0x4f, 0xa2, 0x97, 0x2e, 0x63, 0x1f, 0x38,
+ 0x25, 0x1c, 0xb8, 0xf8, 0xec, 0xc0, 0x60, 0x14, 0x9a, 0x9d, 0x91, 0xc0,
+ 0x0e, 0xbb, 0x23, 0xfc, 0x25, 0x8b, 0x01, 0x20, 0x2d, 0x30, 0x0f, 0x25,
+ 0xa7, 0x0a, 0xbe, 0x91, 0xf3, 0xb5, 0x15, 0x77, 0x07, 0x59, 0x4a, 0x3a,
+ 0xc7, 0x1b, 0xb9, 0xc9, 0x48, 0xa4, 0xfe, 0x05, 0xe2, 0x50, 0x89, 0x26,
+ 0xd8, 0x13, 0xe1, 0xd2, 0xe4, 0x5d, 0x34, 0xa3, 0x8f, 0x99, 0x00, 0xd0,
+ 0x11, 0x13, 0x97, 0x4c, 0x41, 0x2d, 0x63, 0xdf, 0xb6, 0xa6, 0xc1, 0xb5,
+ 0x9f, 0x08, 0xda, 0x44, 0xd1, 0x80, 0x1d, 0xe3, 0x82, 0x12, 0x5e, 0xa8,
+ 0x63, 0x8f, 0x74, 0xf2, 0xab, 0xbb, 0xf6, 0xca, 0x2a, 0x51, 0xa2, 0xc2,
+ 0xcc, 0x85, 0x37, 0x85, 0x97, 0x1a, 0x4c, 0x3e
+};
+unsigned int PK3_auth_len = 2048;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/db1.h b/components/service/uefi/smm_variable/test/service/auth_vectors/db1.h
new file mode 100644
index 000000000..075b839a9
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/db1.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char DB1_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x15, 0xc4, 0x07, 0x64, 0x88,
+ 0x06, 0x82, 0x9c, 0x3c, 0x2d, 0x78, 0x10, 0xb2, 0xe0, 0xd2, 0x9e, 0x71,
+ 0x1d, 0x2f, 0xa4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x4b, 0x45, 0x4b, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x4b, 0x45, 0x4b, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xb1, 0x58, 0xde, 0xa8, 0xfb, 0xf9, 0xd2,
+ 0x48, 0x11, 0x0a, 0x52, 0x68, 0xbf, 0x45, 0x97, 0xde, 0xdf, 0x54, 0xb3,
+ 0x6e, 0x36, 0xc5, 0x3a, 0xbb, 0x40, 0x18, 0x66, 0xa7, 0x0e, 0x5d, 0xb1,
+ 0x7a, 0x56, 0x24, 0xc7, 0x0d, 0x7e, 0x37, 0xba, 0x60, 0x6d, 0xf6, 0x81,
+ 0x0a, 0x3d, 0x42, 0xec, 0x79, 0x49, 0x9a, 0x1c, 0x20, 0x08, 0x17, 0xc7,
+ 0xba, 0x26, 0xc1, 0x71, 0x47, 0xc0, 0xe6, 0x29, 0xb8, 0xd0, 0x4f, 0xe9,
+ 0xd2, 0x6f, 0x18, 0x49, 0x9d, 0xfc, 0x4a, 0xcc, 0x26, 0x74, 0xc6, 0x1e,
+ 0xe7, 0x9c, 0x43, 0x2e, 0x09, 0xe0, 0x5a, 0x60, 0xa2, 0x27, 0xc0, 0x14,
+ 0x32, 0x3d, 0xe4, 0x64, 0xf9, 0x25, 0x6b, 0x9c, 0x7a, 0x01, 0xea, 0xdf,
+ 0x71, 0x26, 0xf8, 0x14, 0x89, 0xa0, 0x80, 0xf4, 0x8a, 0x05, 0x54, 0xc4,
+ 0x9a, 0x7b, 0x32, 0x5e, 0x75, 0x0d, 0x1b, 0x8a, 0x38, 0x5c, 0x64, 0x7c,
+ 0xf0, 0x65, 0x9e, 0xdf, 0x58, 0xaa, 0x71, 0xff, 0xc1, 0x20, 0xe1, 0x4b,
+ 0x48, 0x68, 0x71, 0x4b, 0xfc, 0xef, 0x39, 0x8d, 0xae, 0x58, 0x97, 0x65,
+ 0xb5, 0x44, 0x65, 0x33, 0x93, 0xa6, 0xc2, 0xf7, 0x3c, 0x23, 0x25, 0x47,
+ 0x9c, 0x7b, 0xd8, 0x12, 0xbc, 0xba, 0xce, 0xfe, 0x07, 0xe1, 0xc2, 0x9a,
+ 0x43, 0xb1, 0x09, 0x74, 0xea, 0xdd, 0x81, 0x9a, 0x66, 0xe9, 0x6f, 0x75,
+ 0x8b, 0x63, 0x09, 0x9c, 0xf0, 0x85, 0x72, 0xe5, 0x2a, 0x9f, 0x3e, 0x03,
+ 0xa2, 0x11, 0x73, 0xd5, 0xd0, 0x24, 0x59, 0x74, 0x10, 0x45, 0xcf, 0xe0,
+ 0xb1, 0x3b, 0x35, 0x13, 0x92, 0x60, 0xba, 0x75, 0x1e, 0x39, 0xa2, 0x18,
+ 0xb5, 0x23, 0xf6, 0xc1, 0x74, 0x5d, 0x73, 0x17, 0xea, 0xca, 0xdb, 0xc8,
+ 0xc9, 0x9b, 0xf9, 0x83, 0x44, 0x29, 0x0d, 0xb2, 0xd1, 0x8e, 0x8f, 0xbb,
+ 0xd4, 0x42, 0x43, 0x3d, 0xc1, 0x0f, 0xb0, 0x97, 0xaf, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe7, 0x8d, 0x45, 0x79, 0xdf, 0xb1, 0x92,
+ 0x11, 0x72, 0x87, 0x8b, 0x78, 0xf8, 0xa7, 0x0a, 0x5b, 0x96, 0x87, 0x09,
+ 0x5b, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0xe7, 0x8d, 0x45, 0x79, 0xdf, 0xb1, 0x92, 0x11, 0x72, 0x87,
+ 0x8b, 0x78, 0xf8, 0xa7, 0x0a, 0x5b, 0x96, 0x87, 0x09, 0x5b, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x09,
+ 0x51, 0x16, 0xf4, 0xd7, 0x79, 0xb5, 0xb7, 0x8b, 0x0d, 0x92, 0xc1, 0x9b,
+ 0x0a, 0x19, 0x33, 0x4c, 0xf1, 0x00, 0x6a, 0xcd, 0x8f, 0xa5, 0xd0, 0x6e,
+ 0x3e, 0x69, 0x35, 0x38, 0xb4, 0xb5, 0x44, 0x54, 0x36, 0x19, 0x58, 0xa8,
+ 0xf4, 0x7e, 0xac, 0x8d, 0x41, 0x28, 0x79, 0x67, 0x7f, 0x0e, 0xbc, 0x6f,
+ 0xa8, 0x96, 0x5c, 0x9e, 0xe3, 0x3f, 0x31, 0x4a, 0xa5, 0xb0, 0xfd, 0x1e,
+ 0xbb, 0x0a, 0xc9, 0x53, 0x84, 0xf3, 0xa2, 0xe5, 0x1c, 0x80, 0x0a, 0xc5,
+ 0x78, 0x5f, 0xe2, 0x52, 0xae, 0x36, 0x03, 0x98, 0x73, 0x3c, 0xb0, 0xf3,
+ 0xd9, 0xc2, 0x95, 0x68, 0x03, 0xcd, 0xc7, 0x6b, 0x2f, 0x33, 0x38, 0xb5,
+ 0x5a, 0x9b, 0xe7, 0x29, 0x23, 0xb1, 0x6c, 0xa2, 0x9e, 0x8d, 0xee, 0x85,
+ 0x0d, 0x08, 0x16, 0xdd, 0x64, 0x56, 0x34, 0x81, 0xf1, 0x60, 0x9d, 0x2c,
+ 0xed, 0x12, 0xb4, 0x9a, 0x75, 0xfe, 0xc1, 0x3e, 0x8c, 0xf1, 0x59, 0xbd,
+ 0xf5, 0x35, 0xe2, 0xb6, 0x97, 0xaa, 0x57, 0x9b, 0xef, 0x1d, 0xf5, 0xd7,
+ 0x81, 0x45, 0x41, 0x92, 0x6b, 0x68, 0x8c, 0xeb, 0x78, 0x3f, 0x9e, 0xff,
+ 0x30, 0x4a, 0xd8, 0x84, 0x8d, 0x12, 0x4e, 0xbe, 0x2d, 0x87, 0xc4, 0x3a,
+ 0xc6, 0x28, 0x10, 0x56, 0xab, 0x73, 0xce, 0xb4, 0xcc, 0xe6, 0x97, 0x77,
+ 0xa9, 0x47, 0xa2, 0xd5, 0x05, 0x91, 0x2a, 0xcc, 0xe6, 0x0c, 0xf5, 0xd3,
+ 0xb5, 0x97, 0xb3, 0x5a, 0x9e, 0xa1, 0x60, 0x1a, 0xfb, 0x11, 0x8b, 0xa8,
+ 0x63, 0x4a, 0x2b, 0xc5, 0xb3, 0x4f, 0xff, 0xaf, 0x88, 0x15, 0x6c, 0xe7,
+ 0xba, 0x19, 0x6a, 0xd3, 0xc3, 0xfd, 0x31, 0x96, 0x9c, 0x91, 0xba, 0xe9,
+ 0xea, 0xf5, 0x60, 0xda, 0xe9, 0x11, 0xc7, 0x36, 0x2e, 0xf4, 0x1a, 0xde,
+ 0x1a, 0xf7, 0x38, 0x9b, 0x68, 0xa2, 0x86, 0x1e, 0x34, 0x5d, 0x19, 0x9b,
+ 0x82, 0x03, 0xe5, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x4b, 0x45,
+ 0x4b, 0x02, 0x14, 0x15, 0xc4, 0x07, 0x64, 0x88, 0x06, 0x82, 0x9c, 0x3c,
+ 0x2d, 0x78, 0x10, 0xb2, 0xe0, 0xd2, 0x9e, 0x71, 0x1d, 0x2f, 0xa4, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x47, 0xe7, 0xa5,
+ 0x3a, 0x03, 0xf1, 0x89, 0xa3, 0x23, 0x6e, 0xb5, 0xdb, 0xe3, 0x3a, 0x78,
+ 0x5f, 0x8b, 0x69, 0x91, 0x1d, 0x7f, 0xc3, 0x74, 0x24, 0x2c, 0x10, 0xbc,
+ 0xd0, 0xf1, 0x54, 0x14, 0xa7, 0xa3, 0x82, 0xe5, 0xc1, 0x04, 0x2a, 0xb6,
+ 0x9e, 0x0d, 0xe2, 0x28, 0xbe, 0x7a, 0x3d, 0xe5, 0x25, 0x83, 0x6d, 0x85,
+ 0x1a, 0x26, 0xcf, 0x5f, 0x1a, 0xa7, 0x57, 0x69, 0x91, 0xfd, 0xb7, 0x46,
+ 0x33, 0x07, 0xae, 0x0a, 0xdb, 0x33, 0xc8, 0x23, 0x9a, 0x6e, 0xb9, 0x17,
+ 0xd0, 0x77, 0x48, 0x24, 0xee, 0xc9, 0x92, 0x1d, 0x26, 0x3c, 0xe8, 0x26,
+ 0x44, 0x90, 0x1c, 0xb9, 0x06, 0xc4, 0x93, 0x39, 0x57, 0x15, 0x65, 0xd1,
+ 0xd5, 0x42, 0xb4, 0x8b, 0x91, 0xa3, 0xb8, 0xbb, 0x6f, 0x6b, 0xfe, 0x85,
+ 0x89, 0xdc, 0x2e, 0xe7, 0x64, 0x7c, 0x43, 0x46, 0x33, 0x67, 0x9e, 0xf7,
+ 0x46, 0x38, 0x8f, 0xe9, 0xe8, 0x82, 0x1d, 0xc6, 0x5a, 0xfe, 0x63, 0xad,
+ 0xb4, 0xbe, 0xa6, 0x5d, 0x64, 0x60, 0x40, 0x93, 0x2f, 0xac, 0x88, 0xfc,
+ 0x8d, 0x16, 0x50, 0xb9, 0x7e, 0xaa, 0x7d, 0xe2, 0x54, 0x49, 0xf6, 0x5e,
+ 0xe2, 0x6d, 0x17, 0x4e, 0xf8, 0x6f, 0x6f, 0x58, 0xdc, 0x94, 0x9f, 0x2a,
+ 0x31, 0x32, 0x17, 0x54, 0xb4, 0xd9, 0x86, 0x67, 0xf9, 0x05, 0xcd, 0x86,
+ 0xfd, 0x69, 0x5a, 0xfc, 0x1f, 0x36, 0x48, 0x23, 0x6f, 0xf1, 0xf3, 0x91,
+ 0x1f, 0x63, 0xff, 0x07, 0x65, 0x3e, 0xa3, 0x90, 0x4f, 0xdf, 0x21, 0x3b,
+ 0xb2, 0x6e, 0x8a, 0x03, 0xce, 0x05, 0x0d, 0x95, 0x1f, 0x40, 0x00, 0x70,
+ 0x0c, 0x53, 0x37, 0x0d, 0x03, 0x38, 0x18, 0x4a, 0xb7, 0xfb, 0x59, 0x43,
+ 0xc2, 0x9f, 0xf7, 0xf4, 0x27, 0x9f, 0xed, 0x53, 0x22, 0xdf, 0x06, 0x52,
+ 0x82, 0x3e, 0x1c, 0xec, 0xe3, 0x1d, 0xcb, 0x7d, 0xbd, 0xf6, 0x16, 0x48,
+ 0x90, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab,
+ 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03,
+ 0x07, 0x30, 0x82, 0x01, 0xef, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+ 0x2d, 0x56, 0x6b, 0xbb, 0xa5, 0x07, 0xa3, 0xa2, 0x44, 0x17, 0xca, 0x1c,
+ 0xe2, 0xfc, 0xd3, 0x2e, 0x3c, 0x6b, 0x4b, 0x65, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x42, 0x31, 0x30, 0x1e, 0x17, 0x0d,
+ 0x32, 0x34, 0x30, 0x31, 0x32, 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38,
+ 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32,
+ 0x30, 0x30, 0x38, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x42,
+ 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+ 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xac, 0x13,
+ 0xa9, 0xbb, 0x26, 0x22, 0x4c, 0x0f, 0xa9, 0x0a, 0x55, 0xbb, 0x40, 0x66,
+ 0x73, 0xb2, 0x9f, 0x0e, 0x3a, 0xe8, 0x08, 0xce, 0xcd, 0x0d, 0x2b, 0xd9,
+ 0xd1, 0x7e, 0x0b, 0x37, 0x6a, 0xf7, 0x7b, 0xb0, 0x21, 0x24, 0x61, 0x1d,
+ 0xbb, 0x34, 0xb6, 0x28, 0x7b, 0xae, 0x77, 0x5b, 0x78, 0xab, 0x27, 0x5d,
+ 0x65, 0xea, 0xe2, 0x8b, 0x89, 0x05, 0x2c, 0x61, 0xe6, 0x4d, 0x7b, 0x9f,
+ 0xbc, 0xaa, 0x21, 0xff, 0x50, 0x86, 0x17, 0x7d, 0x41, 0x48, 0x80, 0xea,
+ 0x60, 0x2c, 0xe9, 0x66, 0x20, 0x78, 0x84, 0xb6, 0x20, 0x1b, 0x47, 0xbd,
+ 0x71, 0x26, 0x77, 0x4d, 0x41, 0x97, 0x65, 0x6b, 0x08, 0xcb, 0x68, 0xb5,
+ 0xab, 0x73, 0x4a, 0xb8, 0x11, 0x60, 0x16, 0x3b, 0xc7, 0x34, 0x22, 0x01,
+ 0xf7, 0x65, 0xbf, 0xf5, 0x8e, 0x3b, 0x93, 0xc4, 0x9f, 0xf5, 0xe8, 0xc2,
+ 0x1f, 0xf9, 0x9d, 0xce, 0xf5, 0xa1, 0xe6, 0x60, 0x3c, 0xa6, 0xa7, 0xb6,
+ 0xe3, 0xea, 0xc1, 0x18, 0x92, 0xde, 0x01, 0xe5, 0xbd, 0xf9, 0x9a, 0x8c,
+ 0x39, 0x54, 0x67, 0x73, 0x57, 0xaa, 0x26, 0xce, 0x6f, 0x01, 0x7c, 0x29,
+ 0xc1, 0xba, 0xf6, 0xad, 0x5f, 0x55, 0x12, 0x54, 0x65, 0xcd, 0xe6, 0xe5,
+ 0x13, 0x4f, 0xf3, 0xc1, 0xed, 0xba, 0x1f, 0x32, 0x1a, 0x41, 0x02, 0xfe,
+ 0x2b, 0x41, 0x07, 0xce, 0xc1, 0x69, 0x91, 0x93, 0xc8, 0x3d, 0x6d, 0x7c,
+ 0xa8, 0xc8, 0xcb, 0xaa, 0x39, 0xf6, 0x59, 0x6f, 0x40, 0x48, 0xef, 0x16,
+ 0xf7, 0xf3, 0xdf, 0xd5, 0xc2, 0x1a, 0xa6, 0xed, 0xff, 0x05, 0xa5, 0xac,
+ 0x39, 0x32, 0x18, 0xcb, 0xe1, 0x87, 0x0f, 0xf8, 0x04, 0x55, 0x50, 0xb7,
+ 0xfb, 0xa2, 0xa2, 0x05, 0x33, 0xa5, 0x15, 0x46, 0xd8, 0x14, 0x35, 0xd2,
+ 0x08, 0x14, 0x48, 0x15, 0x45, 0x0a, 0x7d, 0xfd, 0xa5, 0x36, 0x7e, 0xd4,
+ 0x23, 0xb9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30,
+ 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x28, 0x8e,
+ 0x10, 0x73, 0x79, 0x18, 0xac, 0xe1, 0xfc, 0xd1, 0x85, 0x96, 0x35, 0x62,
+ 0xc3, 0x6c, 0xff, 0x30, 0x20, 0xcc, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x28, 0x8e, 0x10, 0x73, 0x79,
+ 0x18, 0xac, 0xe1, 0xfc, 0xd1, 0x85, 0x96, 0x35, 0x62, 0xc3, 0x6c, 0xff,
+ 0x30, 0x20, 0xcc, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+ 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x01, 0x00, 0x4a, 0x19, 0x4b, 0x7a, 0xe2, 0x4c, 0xbb, 0x7a,
+ 0xde, 0x38, 0xc0, 0xd2, 0x45, 0x8a, 0x18, 0x9e, 0x80, 0xfa, 0xfb, 0xed,
+ 0x97, 0x0d, 0x29, 0x7a, 0xf3, 0x52, 0xc4, 0xc5, 0xfa, 0x57, 0x0b, 0x63,
+ 0xf5, 0x7b, 0x45, 0x11, 0x7c, 0xed, 0x3e, 0xa1, 0x40, 0xd3, 0xef, 0x51,
+ 0xb8, 0x18, 0x31, 0xba, 0xa4, 0x7f, 0x1f, 0x95, 0x3b, 0xd4, 0xae, 0x89,
+ 0x47, 0xf2, 0x40, 0xa3, 0x04, 0x20, 0x31, 0x55, 0xb7, 0xf7, 0xcd, 0x05,
+ 0x2b, 0x2c, 0xca, 0x55, 0xa6, 0xed, 0x0e, 0x84, 0x43, 0xfb, 0xcd, 0x22,
+ 0xeb, 0xb9, 0x1e, 0xd4, 0x36, 0x49, 0x14, 0xcf, 0xa6, 0x75, 0x53, 0x1a,
+ 0x9b, 0x64, 0x05, 0x18, 0x23, 0xa4, 0x4e, 0xb1, 0x95, 0x24, 0x07, 0xce,
+ 0xca, 0x79, 0x57, 0x3a, 0x7f, 0xd6, 0x02, 0x3e, 0xf7, 0x7a, 0xde, 0x68,
+ 0xd1, 0x5c, 0xc0, 0xbd, 0x60, 0xed, 0x56, 0xf5, 0x9f, 0xa1, 0x94, 0x68,
+ 0x39, 0xa6, 0x9b, 0x9d, 0xdf, 0x98, 0x4a, 0x34, 0x39, 0xcc, 0xd5, 0x38,
+ 0xc8, 0x2e, 0x66, 0x69, 0xaf, 0x6d, 0x46, 0xc8, 0x52, 0xc4, 0x9e, 0x9f,
+ 0xe6, 0x4f, 0xa9, 0xd2, 0xf5, 0x15, 0x9a, 0xa1, 0xaa, 0xab, 0x09, 0x67,
+ 0x76, 0x62, 0x6c, 0x5c, 0xf8, 0x1b, 0x4c, 0x57, 0x77, 0x53, 0x2c, 0xe0,
+ 0x91, 0x8b, 0x63, 0xd3, 0xd0, 0xd4, 0xad, 0x89, 0x6c, 0x3d, 0xe2, 0x9a,
+ 0xe2, 0x75, 0xf5, 0x33, 0xd3, 0x74, 0x1e, 0xd6, 0xd0, 0x5c, 0x41, 0x3e,
+ 0xa2, 0x14, 0x04, 0x90, 0xde, 0xfd, 0x68, 0x5d, 0xbd, 0x87, 0x4f, 0x6c,
+ 0x00, 0xae, 0x94, 0xa4, 0xf0, 0x8b, 0xb4, 0x29, 0x58, 0xd8, 0xd0, 0x9c,
+ 0xa6, 0xd3, 0x62, 0x47, 0xee, 0x8c, 0xf6, 0xeb, 0xe9, 0x99, 0x86, 0x45,
+ 0x55, 0xd7, 0x91, 0xc9, 0xe6, 0xcb, 0x2e, 0xa2, 0x63, 0x16, 0xc9, 0x30,
+ 0xdf, 0x72, 0x59, 0x06, 0xe8, 0x22, 0x6b, 0xda
+};
+unsigned int DB1_auth_len = 2048;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/db2.h b/components/service/uefi/smm_variable/test/service/auth_vectors/db2.h
new file mode 100644
index 000000000..0e7a5f609
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/db2.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char DB2_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0,
+ 0x7a, 0xa6, 0xe6, 0x9b, 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b,
+ 0xc7, 0xa8, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x50, 0x4b, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b, 0x31, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xcb, 0x94, 0x4f, 0x33, 0x47, 0xe3, 0xb3,
+ 0xd0, 0x34, 0x45, 0x48, 0xea, 0x6c, 0x66, 0x8d, 0xb0, 0x97, 0x41, 0xe8,
+ 0x81, 0x7f, 0xab, 0x83, 0xa5, 0x9f, 0xa6, 0x5d, 0x47, 0x9b, 0x60, 0x55,
+ 0xc3, 0x70, 0x2c, 0xf5, 0x96, 0x9f, 0xa8, 0xdb, 0xc0, 0xca, 0x63, 0x7c,
+ 0x34, 0xed, 0x14, 0x9e, 0xc0, 0xbe, 0xab, 0xe4, 0x3b, 0x73, 0xed, 0x62,
+ 0x24, 0xe8, 0x68, 0xa4, 0x14, 0x10, 0x50, 0x8f, 0x7f, 0x59, 0xad, 0xec,
+ 0x16, 0x60, 0xfe, 0x1f, 0x60, 0x3b, 0x9a, 0x7b, 0x7a, 0xc3, 0x3e, 0xf4,
+ 0xcf, 0x39, 0x27, 0x70, 0xb9, 0xd9, 0x0a, 0x40, 0xc7, 0x7f, 0x41, 0x80,
+ 0xd3, 0xe0, 0x22, 0x15, 0x1a, 0x91, 0x0e, 0x4a, 0xa7, 0x52, 0x33, 0x72,
+ 0xf2, 0x46, 0x03, 0x42, 0x36, 0x85, 0x27, 0xf0, 0x2f, 0x9f, 0x56, 0xa4,
+ 0xd5, 0xdc, 0x00, 0xd5, 0x5e, 0xe5, 0x1a, 0x08, 0xae, 0xdc, 0x80, 0xb9,
+ 0xa4, 0xcf, 0x58, 0xf1, 0xd4, 0x38, 0x5f, 0xe1, 0xff, 0x81, 0x01, 0xff,
+ 0x17, 0x77, 0xe7, 0x4b, 0xee, 0x91, 0xaf, 0x3a, 0xf9, 0x73, 0xd9, 0x6f,
+ 0xe9, 0x22, 0x55, 0x15, 0x17, 0xa9, 0xc9, 0xde, 0xfc, 0x63, 0xfc, 0x84,
+ 0x96, 0xb7, 0xf8, 0x40, 0x63, 0x5f, 0x2c, 0x21, 0x20, 0x1e, 0x37, 0x14,
+ 0x1b, 0x4e, 0x76, 0xec, 0x3a, 0xcb, 0xd5, 0xdc, 0xef, 0x96, 0x37, 0x43,
+ 0x46, 0x4c, 0x2e, 0xf4, 0xcb, 0x58, 0x90, 0x91, 0x35, 0x6d, 0xb5, 0x58,
+ 0xb8, 0xb7, 0x74, 0x72, 0x80, 0x3f, 0xb7, 0xd0, 0x1b, 0xca, 0x47, 0x18,
+ 0xc9, 0x99, 0x4d, 0x74, 0x97, 0x57, 0xc4, 0x2f, 0x2e, 0x2a, 0xd0, 0x95,
+ 0xc2, 0x1e, 0x64, 0x8d, 0xbd, 0xd1, 0x7e, 0xf6, 0x6c, 0x44, 0x01, 0x1f,
+ 0x37, 0xc0, 0x67, 0x7a, 0x78, 0x47, 0x21, 0xb4, 0x0d, 0xc6, 0xab, 0x81,
+ 0x7e, 0x1c, 0x10, 0x5d, 0x01, 0x2e, 0xfe, 0x41, 0x93, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4,
+ 0xbb, 0x06, 0xa7, 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66,
+ 0x08, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x18, 0x51, 0xee, 0x40, 0x22, 0xae, 0xa4, 0xbb, 0x06, 0xa7,
+ 0xf2, 0xb0, 0x08, 0xf9, 0x5e, 0x89, 0x08, 0x08, 0x66, 0x08, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3a,
+ 0xae, 0xa0, 0xfa, 0x34, 0x4a, 0x52, 0x24, 0x90, 0x3a, 0xba, 0x33, 0x61,
+ 0x0f, 0xc8, 0x6f, 0xbc, 0x72, 0xf8, 0xc3, 0x98, 0x04, 0xe1, 0xcb, 0xf2,
+ 0x82, 0xfd, 0x83, 0x59, 0x51, 0x23, 0x71, 0xf4, 0xce, 0xe9, 0x36, 0x4d,
+ 0x0a, 0xd3, 0x11, 0x6d, 0x51, 0xb7, 0xd1, 0x9f, 0x9b, 0x85, 0x5c, 0x25,
+ 0x11, 0x9c, 0x13, 0xf6, 0x33, 0xd8, 0xa4, 0x27, 0xef, 0x90, 0x56, 0x21,
+ 0xe3, 0x90, 0x10, 0x2b, 0x50, 0x46, 0x6e, 0x8a, 0x84, 0x3e, 0x30, 0x4c,
+ 0xc2, 0xdf, 0x81, 0x60, 0xdf, 0xb8, 0x06, 0xd8, 0x2f, 0xcf, 0x3f, 0xb8,
+ 0xbe, 0x04, 0xa4, 0xbb, 0xba, 0x65, 0x9f, 0x4e, 0xc4, 0x05, 0xbe, 0x9e,
+ 0xfe, 0xa9, 0x0c, 0x06, 0x81, 0xcc, 0xa4, 0x66, 0xb0, 0x14, 0x48, 0xc9,
+ 0x24, 0x88, 0xd8, 0xdc, 0xf2, 0x5c, 0xb5, 0x59, 0x66, 0x4f, 0xc6, 0xa4,
+ 0xa3, 0x96, 0xa8, 0x48, 0x3b, 0x43, 0xff, 0xe0, 0x10, 0x53, 0x79, 0x47,
+ 0x74, 0xe8, 0xbc, 0xa9, 0x4f, 0x8e, 0x1f, 0xfb, 0xf8, 0xad, 0x8d, 0x10,
+ 0x80, 0x8f, 0x80, 0xf8, 0x5b, 0x36, 0xff, 0x60, 0x0b, 0x3f, 0xb2, 0x2f,
+ 0x46, 0x27, 0x43, 0x00, 0x1a, 0x0d, 0xb8, 0x91, 0x4e, 0x84, 0xb1, 0x94,
+ 0xc2, 0xca, 0xd6, 0x36, 0x4d, 0xc6, 0xda, 0x53, 0x71, 0xcc, 0xc8, 0x8e,
+ 0x9c, 0xdb, 0x31, 0xbb, 0x93, 0x49, 0xa7, 0xf4, 0x0b, 0x19, 0xcb, 0xaa,
+ 0x2b, 0x0c, 0xf4, 0xc7, 0x59, 0x8a, 0xc6, 0x59, 0x0b, 0x1d, 0x2f, 0xc3,
+ 0xcf, 0x06, 0xcf, 0x2e, 0x6b, 0x15, 0x6f, 0xba, 0xd1, 0xfa, 0x7d, 0x7f,
+ 0xaa, 0x99, 0x09, 0x63, 0xa8, 0xdd, 0x6c, 0xdb, 0x6a, 0x5e, 0x00, 0x5e,
+ 0x89, 0x11, 0xe3, 0xbd, 0xf6, 0xcb, 0x13, 0x89, 0x6a, 0xb8, 0x7e, 0x89,
+ 0xbc, 0xa5, 0xec, 0x68, 0x85, 0xf0, 0xaa, 0x05, 0x91, 0xc1, 0x79, 0xa1,
+ 0x1c, 0x9d, 0x32, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x4b,
+ 0x31, 0x02, 0x14, 0x71, 0x90, 0xc6, 0x30, 0xd0, 0x7a, 0xa6, 0xe6, 0x9b,
+ 0x3f, 0x3b, 0x01, 0x47, 0x16, 0xad, 0x20, 0x9b, 0xc7, 0xa8, 0x37, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x24, 0xbc, 0xc9,
+ 0xe6, 0x25, 0x6f, 0xae, 0x65, 0x4c, 0x09, 0x7e, 0xc2, 0x9e, 0xdc, 0xdc,
+ 0xec, 0x77, 0x7f, 0x2d, 0x82, 0xa6, 0xff, 0x87, 0xab, 0xe8, 0x3d, 0x47,
+ 0x5b, 0x68, 0x82, 0xed, 0xd2, 0x15, 0x13, 0x07, 0x2f, 0x55, 0x7d, 0xf6,
+ 0x96, 0x00, 0x2f, 0x15, 0x6b, 0x55, 0x9b, 0x92, 0xeb, 0xf9, 0x86, 0x02,
+ 0xf1, 0xee, 0x18, 0x2c, 0xcb, 0x38, 0x1e, 0xb7, 0xfb, 0x4a, 0x18, 0x58,
+ 0xcc, 0x68, 0x35, 0xa8, 0x76, 0xb8, 0x1f, 0x23, 0x3c, 0x2a, 0x58, 0x5f,
+ 0xab, 0xf9, 0xf0, 0x3e, 0xd4, 0xa5, 0xfc, 0x17, 0xf0, 0x11, 0x28, 0x7a,
+ 0xcd, 0x4d, 0x38, 0x9c, 0xaf, 0xd2, 0xbf, 0x15, 0x09, 0xc0, 0x66, 0x8b,
+ 0x93, 0xc2, 0x08, 0x1b, 0x2e, 0x26, 0x97, 0x52, 0x4c, 0x0e, 0x5c, 0x2a,
+ 0x4a, 0xc3, 0x23, 0x03, 0xa0, 0x80, 0x7f, 0x51, 0xa0, 0xc8, 0x27, 0x86,
+ 0x63, 0x07, 0xa7, 0x51, 0x53, 0x8c, 0xe0, 0x18, 0xff, 0x4a, 0x4b, 0xbb,
+ 0x55, 0x71, 0x27, 0x70, 0x19, 0xfa, 0xdd, 0x3e, 0x06, 0x4d, 0xe1, 0x54,
+ 0x29, 0x8c, 0x40, 0xc6, 0x68, 0x63, 0xbb, 0x06, 0xb6, 0xf6, 0x8b, 0x5b,
+ 0x4c, 0x70, 0xcd, 0xd1, 0x01, 0xd2, 0x0a, 0x58, 0x7c, 0xf3, 0xc6, 0xbb,
+ 0x4b, 0xcc, 0x55, 0xf6, 0xeb, 0xb2, 0xd9, 0x46, 0xd1, 0x01, 0x99, 0x9c,
+ 0x2d, 0xd2, 0xb8, 0xf1, 0x6d, 0x12, 0x92, 0xf5, 0xa7, 0x44, 0x65, 0x3c,
+ 0xff, 0xb9, 0xe5, 0x2e, 0xe0, 0x0f, 0x1c, 0x34, 0x0d, 0x6f, 0x2a, 0xcb,
+ 0xc1, 0x51, 0xaf, 0x5f, 0xc5, 0x81, 0x5e, 0x05, 0xe2, 0xf0, 0x49, 0x7f,
+ 0x6f, 0x35, 0x87, 0x17, 0x67, 0x26, 0x15, 0xf4, 0x3e, 0xe1, 0xc8, 0x7a,
+ 0x13, 0xff, 0x52, 0x84, 0x8a, 0x84, 0xe8, 0x09, 0x29, 0xcd, 0x5e, 0xb0,
+ 0xae, 0xe4, 0x16, 0x7d, 0x97, 0xce, 0x9d, 0xfe, 0xa7, 0x9d, 0x7a, 0x6a,
+ 0x1d, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab,
+ 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03,
+ 0x07, 0x30, 0x82, 0x01, 0xef, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+ 0x6c, 0xb7, 0xb7, 0x7d, 0xfe, 0xe4, 0x37, 0x58, 0x0b, 0x5b, 0x5c, 0x4f,
+ 0x25, 0x15, 0x57, 0x19, 0x3d, 0x4c, 0x6c, 0xc4, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x42, 0x32, 0x30, 0x1e, 0x17, 0x0d,
+ 0x32, 0x34, 0x30, 0x31, 0x32, 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38,
+ 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32,
+ 0x30, 0x30, 0x38, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x42,
+ 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+ 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdd, 0xda,
+ 0x18, 0xf9, 0x43, 0x61, 0xe4, 0x9b, 0x1e, 0x0a, 0x6c, 0x97, 0xfc, 0x3e,
+ 0x9d, 0x0f, 0x80, 0xac, 0xbc, 0x0a, 0xbe, 0x4c, 0x78, 0x7a, 0xa2, 0x41,
+ 0xe5, 0x0e, 0x43, 0x41, 0xe4, 0xb5, 0x8a, 0xb2, 0x5e, 0xa2, 0x49, 0x97,
+ 0xe1, 0x20, 0x33, 0xb0, 0x13, 0xb3, 0x15, 0xf5, 0x33, 0x83, 0x78, 0x53,
+ 0x40, 0x14, 0xc5, 0x07, 0xa6, 0xde, 0xf9, 0x5e, 0xe9, 0xa5, 0x75, 0x97,
+ 0xbb, 0xf9, 0xd4, 0xf2, 0x44, 0x8f, 0x7c, 0x98, 0x58, 0x34, 0xb4, 0x2c,
+ 0x1d, 0x70, 0x28, 0xf6, 0x37, 0x63, 0x68, 0x15, 0xae, 0x09, 0x12, 0x3d,
+ 0x69, 0xf6, 0x7d, 0x5e, 0x5b, 0x37, 0xa1, 0x7b, 0x4e, 0x34, 0xb2, 0x44,
+ 0xe8, 0x0a, 0x0b, 0xbb, 0x61, 0xf6, 0xda, 0xcf, 0x93, 0xc9, 0x34, 0xbc,
+ 0x5e, 0x05, 0x5e, 0x42, 0x8d, 0x1e, 0x8a, 0x2c, 0x33, 0x4f, 0xc6, 0x12,
+ 0x92, 0x74, 0x8e, 0x0e, 0x9e, 0x3c, 0x20, 0xf9, 0x69, 0xb8, 0xf1, 0x36,
+ 0xe7, 0xdb, 0x73, 0x9a, 0x59, 0x93, 0xfe, 0xb1, 0x6d, 0x3f, 0x90, 0xcd,
+ 0x06, 0x2c, 0x23, 0x30, 0x89, 0x5d, 0xc0, 0xf1, 0xec, 0xc3, 0x1b, 0x13,
+ 0x4a, 0xc7, 0x55, 0xbb, 0x6f, 0x58, 0x12, 0xa4, 0xaf, 0xc0, 0x6a, 0x7e,
+ 0x8a, 0x8d, 0xa1, 0x1d, 0xe6, 0xf7, 0x84, 0x9c, 0xc2, 0x4a, 0x5f, 0xd3,
+ 0x63, 0xeb, 0x61, 0x7d, 0x60, 0x66, 0x20, 0xe4, 0xa7, 0x98, 0x17, 0x1b,
+ 0x57, 0x3b, 0xe5, 0x53, 0x22, 0x14, 0x4c, 0x0a, 0x4d, 0x4d, 0x1e, 0x71,
+ 0x32, 0x11, 0x11, 0x22, 0xbe, 0x80, 0x90, 0x81, 0x9d, 0xb5, 0xdc, 0x96,
+ 0x50, 0x3b, 0x6f, 0x16, 0x42, 0xab, 0x59, 0xa7, 0x8a, 0xda, 0xcb, 0x5d,
+ 0x33, 0x19, 0x5d, 0x5e, 0x63, 0x8e, 0x64, 0x4e, 0x57, 0x1e, 0x11, 0xb5,
+ 0x6a, 0xa9, 0x34, 0x77, 0x42, 0xa9, 0xab, 0x45, 0xd3, 0x57, 0xb2, 0x48,
+ 0xb0, 0xd7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30,
+ 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9e, 0x35,
+ 0x7c, 0xbf, 0x09, 0x7f, 0x5c, 0xb8, 0x3f, 0x5f, 0xf1, 0x2d, 0xd2, 0x45,
+ 0xcc, 0x21, 0xfe, 0x4d, 0x74, 0x19, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x9e, 0x35, 0x7c, 0xbf, 0x09,
+ 0x7f, 0x5c, 0xb8, 0x3f, 0x5f, 0xf1, 0x2d, 0xd2, 0x45, 0xcc, 0x21, 0xfe,
+ 0x4d, 0x74, 0x19, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+ 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x01, 0x00, 0x23, 0x06, 0x8e, 0x17, 0x9f, 0xe8, 0x61, 0x2e,
+ 0x40, 0xc0, 0x60, 0xa3, 0x8c, 0x7b, 0xf8, 0x3a, 0x45, 0x45, 0xe4, 0xdd,
+ 0x30, 0x0a, 0x6b, 0x3d, 0x4c, 0x57, 0xd8, 0x89, 0x65, 0x16, 0x47, 0xe2,
+ 0xb1, 0x82, 0xdf, 0x02, 0x18, 0x0b, 0xb4, 0xba, 0xea, 0xe9, 0xde, 0xb5,
+ 0xb8, 0x7c, 0x70, 0xb1, 0xf0, 0x59, 0xc2, 0xeb, 0x57, 0xa6, 0x09, 0x2d,
+ 0x0e, 0x83, 0xe0, 0x4e, 0x5a, 0xa1, 0x84, 0x2c, 0x46, 0x05, 0x38, 0x5c,
+ 0x7f, 0xab, 0xc5, 0xc8, 0x34, 0x39, 0xbb, 0xf1, 0x2c, 0xa2, 0x07, 0x14,
+ 0x8f, 0x35, 0x8e, 0x79, 0xb6, 0x5a, 0x02, 0x24, 0x53, 0xe3, 0xc7, 0x59,
+ 0x3a, 0x79, 0x0c, 0x43, 0xd4, 0xb8, 0x5c, 0x38, 0x91, 0x00, 0x42, 0xc9,
+ 0x64, 0x8e, 0x6e, 0x81, 0x12, 0x0f, 0x2b, 0xce, 0x4d, 0x19, 0x7f, 0xa7,
+ 0x8d, 0xc8, 0x7f, 0x80, 0xd1, 0xa9, 0xb7, 0x4a, 0xdf, 0x1a, 0x42, 0xc7,
+ 0x7e, 0x96, 0x12, 0x31, 0x6f, 0xdc, 0x11, 0x1a, 0x4e, 0x2b, 0xbd, 0x4f,
+ 0xbd, 0x4f, 0x17, 0x0d, 0x7e, 0x26, 0x46, 0xf4, 0xc5, 0x1a, 0x55, 0x6a,
+ 0x1b, 0x00, 0x5f, 0xa3, 0x9f, 0xec, 0x97, 0x32, 0xc0, 0x49, 0x5b, 0xe8,
+ 0xd8, 0x66, 0x11, 0x61, 0x16, 0x7d, 0x7a, 0x39, 0x24, 0x4b, 0x07, 0xc8,
+ 0x33, 0xb3, 0x54, 0xcf, 0xfd, 0x7b, 0xb9, 0x61, 0xac, 0x6e, 0x5b, 0xa0,
+ 0x7c, 0x20, 0x1a, 0x3b, 0xfa, 0x01, 0x24, 0x52, 0x75, 0x40, 0x17, 0x49,
+ 0xc5, 0xbc, 0x27, 0x2e, 0xf4, 0x83, 0x54, 0x16, 0xdc, 0x73, 0x14, 0x3e,
+ 0x49, 0x79, 0xe3, 0xea, 0xd7, 0x98, 0xe4, 0xc3, 0xb8, 0x46, 0x82, 0x22,
+ 0xe6, 0xe9, 0xb9, 0x5d, 0x0e, 0xa5, 0xe8, 0x66, 0x1b, 0x31, 0x7c, 0x83,
+ 0xd8, 0x70, 0x95, 0x51, 0x99, 0xe9, 0x38, 0x77, 0x19, 0xef, 0xbe, 0xfd,
+ 0xcb, 0x5a, 0x9e, 0xcd, 0x0e, 0x7f, 0x92, 0x3b
+};
+unsigned int DB2_auth_len = 2048;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/var.h b/components/service/uefi/smm_variable/test/service/auth_vectors/var.h
new file mode 100644
index 000000000..e2ae64ad6
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/var.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char VAR_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x2d, 0x56, 0x6b, 0xbb, 0xa5,
+ 0x07, 0xa3, 0xa2, 0x44, 0x17, 0xca, 0x1c, 0xe2, 0xfc, 0xd3, 0x2e, 0x3c,
+ 0x6b, 0x4b, 0x65, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x44, 0x42, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x42, 0x31, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xac, 0x13, 0xa9, 0xbb, 0x26, 0x22, 0x4c,
+ 0x0f, 0xa9, 0x0a, 0x55, 0xbb, 0x40, 0x66, 0x73, 0xb2, 0x9f, 0x0e, 0x3a,
+ 0xe8, 0x08, 0xce, 0xcd, 0x0d, 0x2b, 0xd9, 0xd1, 0x7e, 0x0b, 0x37, 0x6a,
+ 0xf7, 0x7b, 0xb0, 0x21, 0x24, 0x61, 0x1d, 0xbb, 0x34, 0xb6, 0x28, 0x7b,
+ 0xae, 0x77, 0x5b, 0x78, 0xab, 0x27, 0x5d, 0x65, 0xea, 0xe2, 0x8b, 0x89,
+ 0x05, 0x2c, 0x61, 0xe6, 0x4d, 0x7b, 0x9f, 0xbc, 0xaa, 0x21, 0xff, 0x50,
+ 0x86, 0x17, 0x7d, 0x41, 0x48, 0x80, 0xea, 0x60, 0x2c, 0xe9, 0x66, 0x20,
+ 0x78, 0x84, 0xb6, 0x20, 0x1b, 0x47, 0xbd, 0x71, 0x26, 0x77, 0x4d, 0x41,
+ 0x97, 0x65, 0x6b, 0x08, 0xcb, 0x68, 0xb5, 0xab, 0x73, 0x4a, 0xb8, 0x11,
+ 0x60, 0x16, 0x3b, 0xc7, 0x34, 0x22, 0x01, 0xf7, 0x65, 0xbf, 0xf5, 0x8e,
+ 0x3b, 0x93, 0xc4, 0x9f, 0xf5, 0xe8, 0xc2, 0x1f, 0xf9, 0x9d, 0xce, 0xf5,
+ 0xa1, 0xe6, 0x60, 0x3c, 0xa6, 0xa7, 0xb6, 0xe3, 0xea, 0xc1, 0x18, 0x92,
+ 0xde, 0x01, 0xe5, 0xbd, 0xf9, 0x9a, 0x8c, 0x39, 0x54, 0x67, 0x73, 0x57,
+ 0xaa, 0x26, 0xce, 0x6f, 0x01, 0x7c, 0x29, 0xc1, 0xba, 0xf6, 0xad, 0x5f,
+ 0x55, 0x12, 0x54, 0x65, 0xcd, 0xe6, 0xe5, 0x13, 0x4f, 0xf3, 0xc1, 0xed,
+ 0xba, 0x1f, 0x32, 0x1a, 0x41, 0x02, 0xfe, 0x2b, 0x41, 0x07, 0xce, 0xc1,
+ 0x69, 0x91, 0x93, 0xc8, 0x3d, 0x6d, 0x7c, 0xa8, 0xc8, 0xcb, 0xaa, 0x39,
+ 0xf6, 0x59, 0x6f, 0x40, 0x48, 0xef, 0x16, 0xf7, 0xf3, 0xdf, 0xd5, 0xc2,
+ 0x1a, 0xa6, 0xed, 0xff, 0x05, 0xa5, 0xac, 0x39, 0x32, 0x18, 0xcb, 0xe1,
+ 0x87, 0x0f, 0xf8, 0x04, 0x55, 0x50, 0xb7, 0xfb, 0xa2, 0xa2, 0x05, 0x33,
+ 0xa5, 0x15, 0x46, 0xd8, 0x14, 0x35, 0xd2, 0x08, 0x14, 0x48, 0x15, 0x45,
+ 0x0a, 0x7d, 0xfd, 0xa5, 0x36, 0x7e, 0xd4, 0x23, 0xb9, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x28, 0x8e, 0x10, 0x73, 0x79, 0x18, 0xac,
+ 0xe1, 0xfc, 0xd1, 0x85, 0x96, 0x35, 0x62, 0xc3, 0x6c, 0xff, 0x30, 0x20,
+ 0xcc, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x28, 0x8e, 0x10, 0x73, 0x79, 0x18, 0xac, 0xe1, 0xfc, 0xd1,
+ 0x85, 0x96, 0x35, 0x62, 0xc3, 0x6c, 0xff, 0x30, 0x20, 0xcc, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a,
+ 0x19, 0x4b, 0x7a, 0xe2, 0x4c, 0xbb, 0x7a, 0xde, 0x38, 0xc0, 0xd2, 0x45,
+ 0x8a, 0x18, 0x9e, 0x80, 0xfa, 0xfb, 0xed, 0x97, 0x0d, 0x29, 0x7a, 0xf3,
+ 0x52, 0xc4, 0xc5, 0xfa, 0x57, 0x0b, 0x63, 0xf5, 0x7b, 0x45, 0x11, 0x7c,
+ 0xed, 0x3e, 0xa1, 0x40, 0xd3, 0xef, 0x51, 0xb8, 0x18, 0x31, 0xba, 0xa4,
+ 0x7f, 0x1f, 0x95, 0x3b, 0xd4, 0xae, 0x89, 0x47, 0xf2, 0x40, 0xa3, 0x04,
+ 0x20, 0x31, 0x55, 0xb7, 0xf7, 0xcd, 0x05, 0x2b, 0x2c, 0xca, 0x55, 0xa6,
+ 0xed, 0x0e, 0x84, 0x43, 0xfb, 0xcd, 0x22, 0xeb, 0xb9, 0x1e, 0xd4, 0x36,
+ 0x49, 0x14, 0xcf, 0xa6, 0x75, 0x53, 0x1a, 0x9b, 0x64, 0x05, 0x18, 0x23,
+ 0xa4, 0x4e, 0xb1, 0x95, 0x24, 0x07, 0xce, 0xca, 0x79, 0x57, 0x3a, 0x7f,
+ 0xd6, 0x02, 0x3e, 0xf7, 0x7a, 0xde, 0x68, 0xd1, 0x5c, 0xc0, 0xbd, 0x60,
+ 0xed, 0x56, 0xf5, 0x9f, 0xa1, 0x94, 0x68, 0x39, 0xa6, 0x9b, 0x9d, 0xdf,
+ 0x98, 0x4a, 0x34, 0x39, 0xcc, 0xd5, 0x38, 0xc8, 0x2e, 0x66, 0x69, 0xaf,
+ 0x6d, 0x46, 0xc8, 0x52, 0xc4, 0x9e, 0x9f, 0xe6, 0x4f, 0xa9, 0xd2, 0xf5,
+ 0x15, 0x9a, 0xa1, 0xaa, 0xab, 0x09, 0x67, 0x76, 0x62, 0x6c, 0x5c, 0xf8,
+ 0x1b, 0x4c, 0x57, 0x77, 0x53, 0x2c, 0xe0, 0x91, 0x8b, 0x63, 0xd3, 0xd0,
+ 0xd4, 0xad, 0x89, 0x6c, 0x3d, 0xe2, 0x9a, 0xe2, 0x75, 0xf5, 0x33, 0xd3,
+ 0x74, 0x1e, 0xd6, 0xd0, 0x5c, 0x41, 0x3e, 0xa2, 0x14, 0x04, 0x90, 0xde,
+ 0xfd, 0x68, 0x5d, 0xbd, 0x87, 0x4f, 0x6c, 0x00, 0xae, 0x94, 0xa4, 0xf0,
+ 0x8b, 0xb4, 0x29, 0x58, 0xd8, 0xd0, 0x9c, 0xa6, 0xd3, 0x62, 0x47, 0xee,
+ 0x8c, 0xf6, 0xeb, 0xe9, 0x99, 0x86, 0x45, 0x55, 0xd7, 0x91, 0xc9, 0xe6,
+ 0xcb, 0x2e, 0xa2, 0x63, 0x16, 0xc9, 0x30, 0xdf, 0x72, 0x59, 0x06, 0xe8,
+ 0x22, 0x6b, 0xda, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x42,
+ 0x31, 0x02, 0x14, 0x2d, 0x56, 0x6b, 0xbb, 0xa5, 0x07, 0xa3, 0xa2, 0x44,
+ 0x17, 0xca, 0x1c, 0xe2, 0xfc, 0xd3, 0x2e, 0x3c, 0x6b, 0x4b, 0x65, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x08, 0xd6, 0x61,
+ 0x1c, 0xfb, 0x7a, 0x2b, 0xfb, 0xac, 0x1e, 0x16, 0xb2, 0xa5, 0xde, 0x17,
+ 0xc0, 0xb5, 0x96, 0x36, 0xff, 0x7d, 0xd8, 0x1e, 0x87, 0xfa, 0x74, 0xbc,
+ 0xbb, 0xef, 0x01, 0x54, 0xd4, 0x1c, 0x85, 0xc5, 0xc7, 0x65, 0x08, 0xc3,
+ 0x43, 0x27, 0xbe, 0x8e, 0x7b, 0x18, 0xfc, 0x46, 0x60, 0x81, 0xb0, 0x34,
+ 0x59, 0x52, 0x76, 0x30, 0xf9, 0x64, 0x56, 0xc2, 0x80, 0x2d, 0xad, 0xf6,
+ 0x2a, 0x8e, 0x5b, 0x77, 0xf3, 0xe4, 0x14, 0xef, 0xd3, 0x7f, 0x70, 0xd8,
+ 0x61, 0x82, 0xcc, 0x6a, 0xa9, 0xee, 0x7c, 0x2d, 0x02, 0xd5, 0x47, 0x3c,
+ 0xd7, 0xf4, 0xe5, 0xf8, 0xfc, 0xfc, 0x62, 0xea, 0x55, 0x56, 0x85, 0x92,
+ 0x22, 0x28, 0x64, 0x05, 0x85, 0xd2, 0x02, 0xba, 0xcd, 0x72, 0xb3, 0x76,
+ 0xfd, 0x0b, 0xcd, 0xe0, 0xa4, 0xd5, 0xa6, 0x52, 0x62, 0x74, 0x18, 0x7d,
+ 0x3c, 0xa6, 0x8e, 0x7b, 0x3a, 0x5f, 0xaa, 0x78, 0x30, 0x89, 0x5d, 0xe5,
+ 0x35, 0x33, 0x39, 0x62, 0x79, 0x47, 0x63, 0x33, 0x1e, 0xbd, 0xab, 0xc0,
+ 0xbf, 0x4f, 0x32, 0xf3, 0x07, 0x51, 0x6b, 0xc1, 0xde, 0xbe, 0xa9, 0xf8,
+ 0xa9, 0xaa, 0xd1, 0x0e, 0xc4, 0x00, 0x09, 0x08, 0xb6, 0x92, 0x2e, 0x25,
+ 0x12, 0xcf, 0x76, 0x44, 0x8e, 0xf4, 0x56, 0xf1, 0xee, 0xce, 0x40, 0x51,
+ 0x5d, 0xef, 0xbe, 0x40, 0xa1, 0x6a, 0x75, 0xbd, 0x2b, 0x3e, 0x80, 0x90,
+ 0x71, 0xa9, 0x13, 0x68, 0xef, 0x48, 0xfb, 0x41, 0xb9, 0x9f, 0x8c, 0x93,
+ 0xa6, 0xc6, 0xc1, 0x96, 0x62, 0x05, 0x1d, 0x61, 0x5a, 0xb4, 0x6c, 0x36,
+ 0xd8, 0x5f, 0x57, 0x03, 0xdd, 0xa0, 0xad, 0x00, 0x39, 0x1d, 0xe6, 0x3c,
+ 0xa0, 0x27, 0x98, 0xaa, 0x41, 0x34, 0x58, 0x04, 0x5c, 0x8a, 0xff, 0x46,
+ 0x00, 0x42, 0xe7, 0x3f, 0x10, 0x77, 0xc6, 0x1e, 0x21, 0x0a, 0xd5, 0xe8,
+ 0x57, 0x54, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x20, 0x27, 0x74,
+ 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69,
+ 0x63, 0x65, 0x27, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20,
+ 0x61, 0x73, 0x20, 0x61, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x70, 0x70,
+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61,
+ 0x74, 0x20, 0x72, 0x75, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x6e,
+ 0x20, 0x69, 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x70, 0x72,
+ 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x76,
+ 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x20, 0x4f, 0x74,
+ 0x68, 0x65, 0x72, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72, 0x65, 0x6c, 0x79, 0x20, 0x6f, 0x6e,
+ 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65, 0x72,
+ 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x65, 0x72,
+ 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+ 0x79, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x6f, 0x70,
+ 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x0a,
+ 0x61, 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61,
+ 0x76, 0x6f, 0x69, 0x64, 0x73, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x69,
+ 0x6e, 0x67, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x20, 0x64, 0x61,
+ 0x74, 0x61, 0x20, 0x62, 0x65, 0x79, 0x6f, 0x6e, 0x64, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x69, 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d,
+ 0x65, 0x6e, 0x74, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x6f, 0x72,
+ 0x64, 0x20, 0x27, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x27, 0x0a,
+ 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6d, 0x70,
+ 0x6c, 0x79, 0x20, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20,
+ 0x69, 0x6e, 0x68, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x20, 0x74,
+ 0x72, 0x75, 0x73, 0x74, 0x77, 0x6f, 0x72, 0x74, 0x68, 0x79, 0x20, 0x61,
+ 0x62, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69,
+ 0x63, 0x65, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x20, 0x62, 0x75, 0x74, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65,
+ 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72,
+ 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x0a, 0x70, 0x75, 0x74, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20,
+ 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69,
+ 0x63, 0x65, 0x2e, 0x20, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x20,
+ 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20,
+ 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20,
+ 0x72, 0x65, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20,
+ 0x72, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x68, 0x61, 0x72,
+ 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x69,
+ 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x0a, 0x69, 0x6d, 0x70, 0x6c, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72,
+ 0x69, 0x74, 0x79, 0x20, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x73,
+ 0x2e, 0x0a, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x41, 0x72, 0x6d, 0x20, 0x41,
+ 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x70,
+ 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x41, 0x2d, 0x70, 0x72,
+ 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x29, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69,
+ 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x20,
+ 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
+ 0x64, 0x20, 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2c, 0x20,
+ 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x73, 0x20, 0x61, 0x20, 0x72,
+ 0x61, 0x6e, 0x67, 0x65, 0x0a, 0x6f, 0x66, 0x20, 0x69, 0x73, 0x6f, 0x6c,
+ 0x61, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
+ 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d,
+ 0x65, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6f, 0x66,
+ 0x66, 0x65, 0x72, 0x20, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65,
+ 0x2d, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x74,
+ 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e,
+ 0x73, 0x74, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x74,
+ 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73,
+ 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x73,
+ 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69,
+ 0x74, 0x79, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65,
+ 0x73, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x65, 0x6e, 0x76,
+ 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72,
+ 0x65, 0x20, 0x73, 0x75, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66,
+ 0x6f, 0x72, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61,
+ 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20,
+ 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x0a, 0x61, 0x63,
+ 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x76, 0x61, 0x6c, 0x75,
+ 0x61, 0x62, 0x6c, 0x65, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x20,
+ 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x73, 0x20, 0x6b, 0x65, 0x79, 0x73,
+ 0x20, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76,
+ 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e,
+ 0x20, 0x54, 0x68, 0x65, 0x20, 0x67, 0x6f, 0x61, 0x6c, 0x20, 0x6f, 0x66,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64,
+ 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x70, 0x72,
+ 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x0a, 0x74, 0x6f, 0x20,
+ 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x61, 0x20, 0x66, 0x72,
+ 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x77,
+ 0x68, 0x69, 0x63, 0x68, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+ 0x79, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65,
+ 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62,
+ 0x65, 0x20, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x2c,
+ 0x20, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20,
+ 0x65, 0x61, 0x73, 0x69, 0x6c, 0x79, 0x20, 0x64, 0x65, 0x70, 0x6c, 0x6f,
+ 0x79, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x0a, 0x72, 0x75, 0x6e, 0x20, 0x69,
+ 0x6e, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x65,
+ 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e,
+ 0x20, 0x41, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20,
+ 0x6f, 0x66, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x73,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20,
+ 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x20,
+ 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x62,
+ 0x61, 0x73, 0x69, 0x63, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20,
+ 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x66, 0x75, 0x6e,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20,
+ 0x61, 0x73, 0x20, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72, 0x61,
+ 0x70, 0x68, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x65, 0x63, 0x75,
+ 0x72, 0x65, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x0a,
+ 0x0a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x6f,
+ 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73,
+ 0x73, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e,
+ 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x3a, 0x0a, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x2a, 0x2a, 0x53, 0x65, 0x63, 0x75,
+ 0x72, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x2a, 0x2a, 0x20, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65,
+ 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x69, 0x73, 0x6f, 0x6c, 0x61,
+ 0x74, 0x65, 0x64, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d,
+ 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64,
+ 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65,
+ 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d,
+ 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d,
+ 0x20, 0x2a, 0x2a, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x61,
+ 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2a,
+ 0x2a, 0x20, 0x2d, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d,
+ 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64,
+ 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x54, 0x45, 0x45, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x2d, 0x20, 0x2a, 0x2a, 0x56, 0x4d, 0x20, 0x62, 0x61, 0x63,
+ 0x6b, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x2a, 0x2a, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x20, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x20,
+ 0x74, 0x68, 0x61, 0x74, 0x20, 0x75, 0x73, 0x65, 0x73, 0x20, 0x61, 0x20,
+ 0x68, 0x79, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x20, 0x74,
+ 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x68, 0x61,
+ 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x65,
+ 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20,
+ 0x69, 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x54,
+ 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x72,
+ 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x73, 0x79, 0x73,
+ 0x74, 0x65, 0x6d, 0x2c, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f,
+ 0x72, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64,
+ 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20,
+ 0x75, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x65, 0x63,
+ 0x75, 0x72, 0x65, 0x20, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f,
+ 0x6e, 0x20, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x20, 0x63, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a,
+ 0x6f, 0x66, 0x20, 0x4f, 0x50, 0x2d, 0x54, 0x45, 0x45, 0x20, 0x74, 0x6f,
+ 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x20, 0x61, 0x20, 0x73, 0x65,
+ 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
+ 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72,
+ 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x74, 0x20, 0x53, 0x2d,
+ 0x45, 0x4c, 0x30, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63,
+ 0x75, 0x72, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x20, 0x73, 0x65, 0x72, 0x76,
+ 0x69, 0x63, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+ 0x73, 0x0a, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x50, 0x53, 0x41, 0x20, 0x72, 0x6f, 0x6f,
+ 0x74, 0x2d, 0x6f, 0x66, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x73,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x20, 0x53, 0x65, 0x72,
+ 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65,
+ 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x75, 0x73,
+ 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x73,
+ 0x69, 0x64, 0x65, 0x20, 0x43, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e,
+ 0x67, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x65, 0x78, 0x70, 0x6f,
+ 0x73, 0x65, 0x20, 0x50, 0x53, 0x41, 0x0a, 0x46, 0x75, 0x6e, 0x63, 0x74,
+ 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x41, 0x50, 0x49, 0x73, 0x2e, 0x20,
+ 0x55, 0x45, 0x46, 0x49, 0x20, 0x53, 0x4d, 0x4d, 0x20, 0x73, 0x65, 0x72,
+ 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x70, 0x72,
+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x53, 0x4d, 0x4d, 0x20, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61,
+ 0x79, 0x2e, 0x0a
+};
+unsigned int VAR_auth_len = 3255;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/var_data.h b/components/service/uefi/smm_variable/test/service/auth_vectors/var_data.h
new file mode 100644
index 000000000..32d70720d
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/var_data.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char var_data_txt[] = {
+ 0x54, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x20, 0x27, 0x74, 0x72,
+ 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x27, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x61,
+ 0x73, 0x20, 0x61, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20,
+ 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x70, 0x70, 0x6c,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74,
+ 0x20, 0x72, 0x75, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x6e, 0x20,
+ 0x69, 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x70, 0x72, 0x6f,
+ 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x76, 0x69,
+ 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x20, 0x4f, 0x74, 0x68,
+ 0x65, 0x72, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x20, 0x72, 0x65, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x20,
+ 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65, 0x72, 0x76,
+ 0x69, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x66,
+ 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,
+ 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x6f, 0x70, 0x65,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x0a, 0x61,
+ 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x76,
+ 0x6f, 0x69, 0x64, 0x73, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x69, 0x6e,
+ 0x67, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x20, 0x64, 0x61, 0x74,
+ 0x61, 0x20, 0x62, 0x65, 0x79, 0x6f, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x69, 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62,
+ 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65,
+ 0x6e, 0x74, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x6f, 0x72, 0x64,
+ 0x20, 0x27, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x27, 0x0a, 0x64,
+ 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6d, 0x70, 0x6c,
+ 0x79, 0x20, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69,
+ 0x6e, 0x68, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x20, 0x74, 0x72,
+ 0x75, 0x73, 0x74, 0x77, 0x6f, 0x72, 0x74, 0x68, 0x79, 0x20, 0x61, 0x62,
+ 0x6f, 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x20, 0x62, 0x75, 0x74, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72,
+ 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20,
+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x0a, 0x70, 0x75, 0x74, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x69,
+ 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x2e, 0x20, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74,
+ 0x68, 0x6f, 0x73, 0x65, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x6f,
+ 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72,
+ 0x65, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x72,
+ 0x61, 0x6e, 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x68, 0x61, 0x72, 0x64,
+ 0x77, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x69, 0x72,
+ 0x6d, 0x77, 0x61, 0x72, 0x65, 0x0a, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69,
+ 0x74, 0x79, 0x20, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x73, 0x2e,
+ 0x0a, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x41, 0x72, 0x6d, 0x20, 0x41, 0x70,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x70, 0x72,
+ 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x41, 0x2d, 0x70, 0x72, 0x6f,
+ 0x66, 0x69, 0x6c, 0x65, 0x29, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74,
+ 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x20, 0x63,
+ 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77,
+ 0x69, 0x74, 0x68, 0x20, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+ 0x20, 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2c, 0x20, 0x70,
+ 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x73, 0x20, 0x61, 0x20, 0x72, 0x61,
+ 0x6e, 0x67, 0x65, 0x0a, 0x6f, 0x66, 0x20, 0x69, 0x73, 0x6f, 0x6c, 0x61,
+ 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69,
+ 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65,
+ 0x6e, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6f, 0x66, 0x66,
+ 0x65, 0x72, 0x20, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2d,
+ 0x62, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x65,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x73,
+ 0x74, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x74, 0x74,
+ 0x61, 0x63, 0x6b, 0x2e, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65,
+ 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x73, 0x74,
+ 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+ 0x79, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73,
+ 0x2c, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x65, 0x6e, 0x76, 0x69,
+ 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65,
+ 0x20, 0x73, 0x75, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x6f,
+ 0x72, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x70,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74,
+ 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x0a, 0x61, 0x63, 0x63,
+ 0x65, 0x73, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x61,
+ 0x62, 0x6c, 0x65, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x20, 0x73,
+ 0x75, 0x63, 0x68, 0x20, 0x61, 0x73, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x20,
+ 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65,
+ 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x20,
+ 0x54, 0x68, 0x65, 0x20, 0x67, 0x6f, 0x61, 0x6c, 0x20, 0x6f, 0x66, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20,
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x70, 0x72, 0x6f,
+ 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x0a, 0x74, 0x6f, 0x20, 0x70,
+ 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x61, 0x20, 0x66, 0x72, 0x61,
+ 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x68,
+ 0x69, 0x63, 0x68, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,
+ 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65, 0x72,
+ 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65,
+ 0x20, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x2c, 0x20,
+ 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65,
+ 0x61, 0x73, 0x69, 0x6c, 0x79, 0x20, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79,
+ 0x65, 0x64, 0x20, 0x74, 0x6f, 0x0a, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e,
+ 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x65, 0x6e,
+ 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x20,
+ 0x41, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x6f,
+ 0x66, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x73, 0x65,
+ 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x69,
+ 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x74,
+ 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x62, 0x61,
+ 0x73, 0x69, 0x63, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x73,
+ 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x66, 0x75, 0x6e, 0x63,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61,
+ 0x73, 0x20, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x70,
+ 0x68, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72,
+ 0x65, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x0a, 0x0a,
+ 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x6f, 0x6c,
+ 0x61, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
+ 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d,
+ 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x3a, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x2d, 0x20, 0x2a, 0x2a, 0x53, 0x65, 0x63, 0x75, 0x72,
+ 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x2a, 0x2a, 0x20, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
+ 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x69, 0x73, 0x6f, 0x6c, 0x61, 0x74,
+ 0x65, 0x64, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65,
+ 0x6e, 0x74, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x20,
+ 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
+ 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x61,
+ 0x6e, 0x61, 0x67, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
+ 0x2a, 0x2a, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x61, 0x70,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2a, 0x2a,
+ 0x20, 0x2d, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65,
+ 0x6e, 0x74, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x20,
+ 0x62, 0x79, 0x20, 0x61, 0x20, 0x54, 0x45, 0x45, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x2d, 0x20, 0x2a, 0x2a, 0x56, 0x4d, 0x20, 0x62, 0x61, 0x63, 0x6b,
+ 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x2a, 0x2a, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+ 0x65, 0x72, 0x20, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x74,
+ 0x68, 0x61, 0x74, 0x20, 0x75, 0x73, 0x65, 0x73, 0x20, 0x61, 0x20, 0x68,
+ 0x79, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x20, 0x74, 0x6f,
+ 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x68, 0x61, 0x72,
+ 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x64,
+ 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x69,
+ 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x54, 0x68,
+ 0x65, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x72, 0x65,
+ 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x73, 0x79, 0x73, 0x74,
+ 0x65, 0x6d, 0x2c, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72,
+ 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x65,
+ 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x75,
+ 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x65, 0x63, 0x75,
+ 0x72, 0x65, 0x20, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+ 0x20, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6f,
+ 0x66, 0x20, 0x4f, 0x50, 0x2d, 0x54, 0x45, 0x45, 0x20, 0x74, 0x6f, 0x20,
+ 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x20, 0x61, 0x20, 0x73, 0x65, 0x74,
+ 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x70,
+ 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72, 0x75,
+ 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x74, 0x20, 0x53, 0x2d, 0x45,
+ 0x4c, 0x30, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x75,
+ 0x72, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69,
+ 0x63, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73,
+ 0x0a, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x20, 0x50, 0x53, 0x41, 0x20, 0x72, 0x6f, 0x6f, 0x74,
+ 0x2d, 0x6f, 0x66, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x73, 0x65,
+ 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x20, 0x53, 0x65, 0x72, 0x76,
+ 0x69, 0x63, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20,
+ 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x75, 0x73, 0x69,
+ 0x6e, 0x67, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x69,
+ 0x64, 0x65, 0x20, 0x43, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67,
+ 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+ 0x65, 0x20, 0x50, 0x53, 0x41, 0x0a, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x41, 0x50, 0x49, 0x73, 0x2e, 0x20, 0x55,
+ 0x45, 0x46, 0x49, 0x20, 0x53, 0x4d, 0x4d, 0x20, 0x73, 0x65, 0x72, 0x76,
+ 0x69, 0x63, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x70, 0x72, 0x6f,
+ 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x53, 0x4d, 0x4d, 0x20, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+ 0x2e, 0x0a
+};
+unsigned int var_data_txt_len = 2030;
diff --git a/components/service/uefi/smm_variable/test/service/auth_vectors/var_delete.h b/components/service/uefi/smm_variable/test/service/auth_vectors/var_delete.h
new file mode 100644
index 000000000..e4b82b5f7
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/auth_vectors/var_delete.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+
+unsigned char VAR_delete_auth[] = {
+ 0xe8, 0x07, 0x01, 0x1a, 0x11, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x0e,
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a, 0xa9, 0x34, 0x7d,
+ 0x37, 0x56, 0x65, 0xa7, 0x30, 0x82, 0x04, 0x9d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x04, 0x8e, 0x30,
+ 0x82, 0x04, 0x8a, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+ 0xa0, 0x82, 0x03, 0x0b, 0x30, 0x82, 0x03, 0x07, 0x30, 0x82, 0x01, 0xef,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x2d, 0x56, 0x6b, 0xbb, 0xa5,
+ 0x07, 0xa3, 0xa2, 0x44, 0x17, 0xca, 0x1c, 0xe2, 0xfc, 0xd3, 0x2e, 0x3c,
+ 0x6b, 0x4b, 0x65, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x44, 0x42, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x31, 0x32,
+ 0x36, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x34,
+ 0x30, 0x31, 0x32, 0x33, 0x31, 0x36, 0x32, 0x30, 0x30, 0x38, 0x5a, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x42, 0x31, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xac, 0x13, 0xa9, 0xbb, 0x26, 0x22, 0x4c,
+ 0x0f, 0xa9, 0x0a, 0x55, 0xbb, 0x40, 0x66, 0x73, 0xb2, 0x9f, 0x0e, 0x3a,
+ 0xe8, 0x08, 0xce, 0xcd, 0x0d, 0x2b, 0xd9, 0xd1, 0x7e, 0x0b, 0x37, 0x6a,
+ 0xf7, 0x7b, 0xb0, 0x21, 0x24, 0x61, 0x1d, 0xbb, 0x34, 0xb6, 0x28, 0x7b,
+ 0xae, 0x77, 0x5b, 0x78, 0xab, 0x27, 0x5d, 0x65, 0xea, 0xe2, 0x8b, 0x89,
+ 0x05, 0x2c, 0x61, 0xe6, 0x4d, 0x7b, 0x9f, 0xbc, 0xaa, 0x21, 0xff, 0x50,
+ 0x86, 0x17, 0x7d, 0x41, 0x48, 0x80, 0xea, 0x60, 0x2c, 0xe9, 0x66, 0x20,
+ 0x78, 0x84, 0xb6, 0x20, 0x1b, 0x47, 0xbd, 0x71, 0x26, 0x77, 0x4d, 0x41,
+ 0x97, 0x65, 0x6b, 0x08, 0xcb, 0x68, 0xb5, 0xab, 0x73, 0x4a, 0xb8, 0x11,
+ 0x60, 0x16, 0x3b, 0xc7, 0x34, 0x22, 0x01, 0xf7, 0x65, 0xbf, 0xf5, 0x8e,
+ 0x3b, 0x93, 0xc4, 0x9f, 0xf5, 0xe8, 0xc2, 0x1f, 0xf9, 0x9d, 0xce, 0xf5,
+ 0xa1, 0xe6, 0x60, 0x3c, 0xa6, 0xa7, 0xb6, 0xe3, 0xea, 0xc1, 0x18, 0x92,
+ 0xde, 0x01, 0xe5, 0xbd, 0xf9, 0x9a, 0x8c, 0x39, 0x54, 0x67, 0x73, 0x57,
+ 0xaa, 0x26, 0xce, 0x6f, 0x01, 0x7c, 0x29, 0xc1, 0xba, 0xf6, 0xad, 0x5f,
+ 0x55, 0x12, 0x54, 0x65, 0xcd, 0xe6, 0xe5, 0x13, 0x4f, 0xf3, 0xc1, 0xed,
+ 0xba, 0x1f, 0x32, 0x1a, 0x41, 0x02, 0xfe, 0x2b, 0x41, 0x07, 0xce, 0xc1,
+ 0x69, 0x91, 0x93, 0xc8, 0x3d, 0x6d, 0x7c, 0xa8, 0xc8, 0xcb, 0xaa, 0x39,
+ 0xf6, 0x59, 0x6f, 0x40, 0x48, 0xef, 0x16, 0xf7, 0xf3, 0xdf, 0xd5, 0xc2,
+ 0x1a, 0xa6, 0xed, 0xff, 0x05, 0xa5, 0xac, 0x39, 0x32, 0x18, 0xcb, 0xe1,
+ 0x87, 0x0f, 0xf8, 0x04, 0x55, 0x50, 0xb7, 0xfb, 0xa2, 0xa2, 0x05, 0x33,
+ 0xa5, 0x15, 0x46, 0xd8, 0x14, 0x35, 0xd2, 0x08, 0x14, 0x48, 0x15, 0x45,
+ 0x0a, 0x7d, 0xfd, 0xa5, 0x36, 0x7e, 0xd4, 0x23, 0xb9, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x28, 0x8e, 0x10, 0x73, 0x79, 0x18, 0xac,
+ 0xe1, 0xfc, 0xd1, 0x85, 0x96, 0x35, 0x62, 0xc3, 0x6c, 0xff, 0x30, 0x20,
+ 0xcc, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x28, 0x8e, 0x10, 0x73, 0x79, 0x18, 0xac, 0xe1, 0xfc, 0xd1,
+ 0x85, 0x96, 0x35, 0x62, 0xc3, 0x6c, 0xff, 0x30, 0x20, 0xcc, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a,
+ 0x19, 0x4b, 0x7a, 0xe2, 0x4c, 0xbb, 0x7a, 0xde, 0x38, 0xc0, 0xd2, 0x45,
+ 0x8a, 0x18, 0x9e, 0x80, 0xfa, 0xfb, 0xed, 0x97, 0x0d, 0x29, 0x7a, 0xf3,
+ 0x52, 0xc4, 0xc5, 0xfa, 0x57, 0x0b, 0x63, 0xf5, 0x7b, 0x45, 0x11, 0x7c,
+ 0xed, 0x3e, 0xa1, 0x40, 0xd3, 0xef, 0x51, 0xb8, 0x18, 0x31, 0xba, 0xa4,
+ 0x7f, 0x1f, 0x95, 0x3b, 0xd4, 0xae, 0x89, 0x47, 0xf2, 0x40, 0xa3, 0x04,
+ 0x20, 0x31, 0x55, 0xb7, 0xf7, 0xcd, 0x05, 0x2b, 0x2c, 0xca, 0x55, 0xa6,
+ 0xed, 0x0e, 0x84, 0x43, 0xfb, 0xcd, 0x22, 0xeb, 0xb9, 0x1e, 0xd4, 0x36,
+ 0x49, 0x14, 0xcf, 0xa6, 0x75, 0x53, 0x1a, 0x9b, 0x64, 0x05, 0x18, 0x23,
+ 0xa4, 0x4e, 0xb1, 0x95, 0x24, 0x07, 0xce, 0xca, 0x79, 0x57, 0x3a, 0x7f,
+ 0xd6, 0x02, 0x3e, 0xf7, 0x7a, 0xde, 0x68, 0xd1, 0x5c, 0xc0, 0xbd, 0x60,
+ 0xed, 0x56, 0xf5, 0x9f, 0xa1, 0x94, 0x68, 0x39, 0xa6, 0x9b, 0x9d, 0xdf,
+ 0x98, 0x4a, 0x34, 0x39, 0xcc, 0xd5, 0x38, 0xc8, 0x2e, 0x66, 0x69, 0xaf,
+ 0x6d, 0x46, 0xc8, 0x52, 0xc4, 0x9e, 0x9f, 0xe6, 0x4f, 0xa9, 0xd2, 0xf5,
+ 0x15, 0x9a, 0xa1, 0xaa, 0xab, 0x09, 0x67, 0x76, 0x62, 0x6c, 0x5c, 0xf8,
+ 0x1b, 0x4c, 0x57, 0x77, 0x53, 0x2c, 0xe0, 0x91, 0x8b, 0x63, 0xd3, 0xd0,
+ 0xd4, 0xad, 0x89, 0x6c, 0x3d, 0xe2, 0x9a, 0xe2, 0x75, 0xf5, 0x33, 0xd3,
+ 0x74, 0x1e, 0xd6, 0xd0, 0x5c, 0x41, 0x3e, 0xa2, 0x14, 0x04, 0x90, 0xde,
+ 0xfd, 0x68, 0x5d, 0xbd, 0x87, 0x4f, 0x6c, 0x00, 0xae, 0x94, 0xa4, 0xf0,
+ 0x8b, 0xb4, 0x29, 0x58, 0xd8, 0xd0, 0x9c, 0xa6, 0xd3, 0x62, 0x47, 0xee,
+ 0x8c, 0xf6, 0xeb, 0xe9, 0x99, 0x86, 0x45, 0x55, 0xd7, 0x91, 0xc9, 0xe6,
+ 0xcb, 0x2e, 0xa2, 0x63, 0x16, 0xc9, 0x30, 0xdf, 0x72, 0x59, 0x06, 0xe8,
+ 0x22, 0x6b, 0xda, 0x31, 0x82, 0x01, 0x56, 0x30, 0x82, 0x01, 0x52, 0x02,
+ 0x01, 0x01, 0x30, 0x2b, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x42,
+ 0x31, 0x02, 0x14, 0x2d, 0x56, 0x6b, 0xbb, 0xa5, 0x07, 0xa3, 0xa2, 0x44,
+ 0x17, 0xca, 0x1c, 0xe2, 0xfc, 0xd3, 0x2e, 0x3c, 0x6b, 0x4b, 0x65, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x59, 0x08, 0x5e,
+ 0x9c, 0xd8, 0x49, 0xdc, 0x09, 0xb9, 0x67, 0x8c, 0x2d, 0x60, 0x2b, 0x66,
+ 0x01, 0x29, 0x88, 0x50, 0x44, 0x3d, 0xc5, 0x03, 0xab, 0x2d, 0x86, 0xe6,
+ 0x2e, 0xd8, 0x0b, 0x94, 0x10, 0xfd, 0x26, 0x38, 0x9e, 0xe4, 0xf7, 0xfc,
+ 0x91, 0x89, 0x95, 0x63, 0x54, 0x99, 0x99, 0xd2, 0xae, 0x66, 0x3a, 0xb2,
+ 0x81, 0x25, 0x94, 0xc9, 0x85, 0x9a, 0x53, 0xf8, 0x37, 0xd3, 0x2b, 0xc3,
+ 0xb7, 0xcf, 0x80, 0x67, 0x8f, 0x04, 0x01, 0x1a, 0xd0, 0x26, 0x8e, 0x3f,
+ 0x01, 0x1c, 0x5d, 0x4c, 0xc8, 0x15, 0x32, 0x54, 0xc1, 0x35, 0x09, 0x90,
+ 0x60, 0x77, 0xcb, 0xe7, 0x93, 0x1e, 0x50, 0x2f, 0x62, 0x71, 0x3a, 0x0f,
+ 0x7f, 0xc5, 0x69, 0xe1, 0xf1, 0x5a, 0x42, 0xcf, 0xad, 0x92, 0x57, 0x2a,
+ 0x99, 0x3b, 0xd6, 0xf6, 0x16, 0x21, 0xed, 0x09, 0xa2, 0x53, 0x24, 0xcf,
+ 0x79, 0x91, 0x75, 0x3f, 0x63, 0x32, 0x2f, 0xf1, 0xcb, 0xaf, 0x4e, 0x45,
+ 0xb6, 0xc2, 0xb8, 0xc3, 0x48, 0xcf, 0x5c, 0xae, 0x36, 0xdb, 0xc7, 0x6d,
+ 0x55, 0xe2, 0x79, 0x3f, 0x0b, 0xb7, 0x7d, 0x9e, 0x11, 0x5c, 0x71, 0xb6,
+ 0xd6, 0x78, 0xe7, 0x75, 0xcd, 0x2b, 0x42, 0x5c, 0xd9, 0x91, 0x17, 0x9b,
+ 0xc7, 0x1a, 0xe3, 0xf2, 0x9e, 0x4f, 0x84, 0x68, 0xf9, 0xa4, 0xd2, 0xc4,
+ 0xcd, 0x2e, 0xa9, 0x35, 0x8c, 0x75, 0xb1, 0xcb, 0xb7, 0x2c, 0x4d, 0xfe,
+ 0xa1, 0x7f, 0xaf, 0x62, 0xf0, 0x26, 0x98, 0x33, 0x05, 0x94, 0x09, 0xbb,
+ 0x94, 0xd6, 0x5e, 0x24, 0xbf, 0xff, 0x4e, 0x9a, 0x32, 0xf8, 0xa4, 0x17,
+ 0x43, 0xb4, 0x9b, 0x50, 0xa2, 0x83, 0x7a, 0x83, 0x97, 0x8d, 0x43, 0x09,
+ 0x36, 0x3c, 0xa1, 0x7d, 0x3d, 0xd0, 0x56, 0x34, 0xe3, 0x00, 0xf6, 0x37,
+ 0x76, 0x13, 0x38, 0xec, 0xc4, 0xb4, 0xaa, 0x59, 0xfa, 0xd6, 0xbc, 0xcd,
+ 0xa6
+};
+unsigned int VAR_delete_auth_len = 1225;
diff --git a/components/service/smm_variable/test/service/component.cmake b/components/service/uefi/smm_variable/test/service/component.cmake
index 4af6aac5e..4af6aac5e 100644
--- a/components/service/smm_variable/test/service/component.cmake
+++ b/components/service/uefi/smm_variable/test/service/component.cmake
diff --git a/components/service/smm_variable/test/service/smm_variable_attack_tests.cpp b/components/service/uefi/smm_variable/test/service/smm_variable_attack_tests.cpp
index ce9aa3ca2..76b62fd35 100644
--- a/components/service/smm_variable/test/service/smm_variable_attack_tests.cpp
+++ b/components/service/uefi/smm_variable/test/service/smm_variable_attack_tests.cpp
@@ -1,14 +1,15 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <CppUTest/TestHarness.h>
+#include <cstring>
#include <limits>
-#include <service/smm_variable/client/cpp/smm_variable_client.h>
#include <protocols/rpc/common/packed-c/encoding.h>
+#include <service/uefi/smm_variable/client/cpp/smm_variable_client.h>
#include <service_locator.h>
-#include <CppUTest/TestHarness.h>
/*
* Attack tests for the smm-variable service. Invalid parameters are sent by
@@ -18,25 +19,24 @@ TEST_GROUP(SmmVariableAttackTests)
{
void setup()
{
- struct rpc_caller *caller;
- int status;
-
- m_rpc_session_handle = NULL;
+ m_rpc_session = NULL;
m_service_context = NULL;
service_locator_init();
- m_service_context =
- service_locator_query("sn:trustedfirmware.org:smm-variable:0", &status);
+ m_service_context = service_locator_query("sn:trustedfirmware.org:smm-variable:0");
CHECK_TRUE(m_service_context);
- m_rpc_session_handle =
- service_context_open(m_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
- CHECK_TRUE(m_rpc_session_handle);
+ m_rpc_session = service_context_open(m_service_context);
+ CHECK_TRUE(m_rpc_session);
- m_client = new smm_variable_client(caller);
+ m_client = new smm_variable_client(m_rpc_session);
setup_common_guid();
+ var_name_1=to_variable_name(u"varibale_1");
+ null_name=to_variable_name(u"");
+ var_name_test=to_variable_name(u"test_variable");
+
}
void teardown()
@@ -44,11 +44,15 @@ TEST_GROUP(SmmVariableAttackTests)
delete m_client;
m_client = NULL;
- service_context_close(m_service_context, m_rpc_session_handle);
- m_rpc_session_handle = NULL;
+ if (m_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
- service_context_relinquish(m_service_context);
- m_service_context = NULL;
+ service_context_relinquish(m_service_context);
+ m_service_context = NULL;
+ }
}
void setup_common_guid()
@@ -66,26 +70,31 @@ TEST_GROUP(SmmVariableAttackTests)
m_common_guid.Data4[7] = 0x07;
}
+ std::u16string to_variable_name(const char16_t *string)
+ {
+ std::u16string var_name(string);
+ var_name.push_back(0);
+
+ return var_name;
+ }
+
smm_variable_client *m_client;
- rpc_session_handle m_rpc_session_handle;
+ struct rpc_caller_session *m_rpc_session;
struct service_context *m_service_context;
EFI_GUID m_common_guid;
+ std::u16string var_name_1;
+ std::u16string null_name;
+ std::u16string var_name_test;
};
TEST(SmmVariableAttackTests, setWithOversizeData)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
std::string set_data = "UEFI variable data string";
/* Override the data size with a big but plausable length */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name,
- set_data,
- 0,
- 0,
- std::numeric_limits<uint16_t>::max());
+ efi_status = m_client->set_variable(m_common_guid, var_name_test, set_data, 0, 0,
+ std::numeric_limits<uint16_t>::max());
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
@@ -93,17 +102,11 @@ TEST(SmmVariableAttackTests, setWithOversizeData)
TEST(SmmVariableAttackTests, setWithSizeMaxDataSize)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
std::string set_data = "UEFI variable data string";
/* Override the data size with SIZE_MAX length */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name,
- set_data,
- 0,
- 0,
- std::numeric_limits<size_t>::max());
+ efi_status = m_client->set_variable(m_common_guid, var_name_test, set_data, 0, 0,
+ std::numeric_limits<size_t>::max());
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
@@ -111,17 +114,11 @@ TEST(SmmVariableAttackTests, setWithSizeMaxDataSize)
TEST(SmmVariableAttackTests, setWithOversizeName)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
std::string set_data = "UEFI variable data string";
/* Override the name size slightly too big such that name + data don't fit */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name,
- set_data,
- 0,
- (var_name.size() + 1) * sizeof(int16_t) + 1,
- 0);
+ efi_status = m_client->set_variable(m_common_guid, var_name_test, set_data, 0,
+ (var_name_test.size() + 1) * sizeof(uint16_t) + 1, 0);
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
@@ -129,17 +126,11 @@ TEST(SmmVariableAttackTests, setWithOversizeName)
TEST(SmmVariableAttackTests, setWithSizeMaxNameSize)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
std::string set_data = "UEFI variable data string";
/* Override the name size slightly too big such that name + data don't fit */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name,
- set_data,
- 0,
- std::numeric_limits<size_t>::max(),
- 0);
+ efi_status = m_client->set_variable(m_common_guid, var_name_test, set_data, 0,
+ std::numeric_limits<size_t>::max(), 0);
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
@@ -147,51 +138,36 @@ TEST(SmmVariableAttackTests, setWithSizeMaxNameSize)
TEST(SmmVariableAttackTests, setAndGetWithOversizeName)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
std::string set_data = "UEFI variable data string";
std::string get_data;
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name,
- set_data,
- 0);
+ efi_status = m_client->set_variable(m_common_guid, var_name_test, set_data, 0);
UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- efi_status = m_client->get_variable(
- m_common_guid,
- var_name,
- get_data,
- (var_name.size() + 1) * sizeof(int16_t) + 1);
+ efi_status = m_client->get_variable(m_common_guid, var_name_test, get_data,
+ (var_name_test.size() + 1) * sizeof(int16_t) + 1);
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
/* Expect remove to be permitted */
- efi_status = m_client->remove_variable(m_common_guid, var_name);
+ efi_status = m_client->remove_variable(m_common_guid, var_name_test);
UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
}
TEST(SmmVariableAttackTests, setAndGetWithSizeMaxNameSize)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"test_variable";
+ const char16_t var_name[] = u"test_variable";
std::string set_data = "UEFI variable data string";
std::string get_data;
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name,
- set_data,
- 0);
+ efi_status = m_client->set_variable(m_common_guid, var_name, set_data, 0);
UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
- efi_status = m_client->get_variable(
- m_common_guid,
- var_name,
- get_data,
- std::numeric_limits<size_t>::max());
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data,
+ std::numeric_limits<size_t>::max());
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
@@ -203,13 +179,12 @@ TEST(SmmVariableAttackTests, setAndGetWithSizeMaxNameSize)
TEST(SmmVariableAttackTests, enumerateWithOversizeName)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name;
- EFI_GUID guid = {0};
+ std::u16string var_name = null_name;
+ EFI_GUID guid;
+ memset(&guid, 0, sizeof(guid));
- efi_status = m_client->get_next_variable_name(
- guid,
- var_name,
- (var_name.size() + 1) * sizeof(int16_t) + 1);
+ efi_status = m_client->get_next_variable_name(guid, var_name,
+ (var_name.size() + 1) * sizeof(int16_t) + 1);
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
@@ -217,29 +192,24 @@ TEST(SmmVariableAttackTests, enumerateWithOversizeName)
TEST(SmmVariableAttackTests, enumerateWithSizeMaxNameSize)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name_1 = L"varibale_1";
- std::wstring var_name;
- EFI_GUID guid = {0};
+ std::u16string var_name=null_name;
+ EFI_GUID guid;
+ memset(&guid, 0, sizeof(guid));
/* Add a variable */
- efi_status = m_client->set_variable(
- m_common_guid,
- var_name_1,
- std::string("Some data"),
- EFI_VARIABLE_NON_VOLATILE);
+ efi_status = m_client->set_variable(m_common_guid, var_name_1, std::string("Some data"),
+ EFI_VARIABLE_NON_VOLATILE);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
/* Initial iteration uses good name length */
- efi_status = m_client->get_next_variable_name(
- guid,
- var_name);
+ efi_status = m_client->get_next_variable_name(guid, var_name);
UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
/* Next iteration uses invalid name length */
- efi_status = m_client->get_next_variable_name(
- guid,
- var_name,
- std::numeric_limits<size_t>::max());
+ efi_status = m_client->get_next_variable_name(guid, var_name,
+ std::numeric_limits<size_t>::max());
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
@@ -251,7 +221,6 @@ TEST(SmmVariableAttackTests, enumerateWithSizeMaxNameSize)
TEST(SmmVariableAttackTests, setCheckPropertyWithOversizeName)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"varibale_1";
VAR_CHECK_VARIABLE_PROPERTY check_property;
check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
@@ -260,18 +229,14 @@ TEST(SmmVariableAttackTests, setCheckPropertyWithOversizeName)
check_property.MinSize = 0;
check_property.MaxSize = 200;
- efi_status = m_client->set_var_check_property(
- m_common_guid,
- var_name,
- check_property,
- (var_name.size() + 1) * sizeof(int16_t) + 1);
+ efi_status = m_client->set_var_check_property(m_common_guid, var_name_1, check_property,
+ (var_name_1.size() + 1) * sizeof(int16_t) + 1);
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
TEST(SmmVariableAttackTests, setCheckPropertyWithMaxSizeName)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"varibale_1";
VAR_CHECK_VARIABLE_PROPERTY check_property;
check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
@@ -280,40 +245,28 @@ TEST(SmmVariableAttackTests, setCheckPropertyWithMaxSizeName)
check_property.MinSize = 0;
check_property.MaxSize = 200;
- efi_status = m_client->set_var_check_property(
- m_common_guid,
- var_name,
- check_property,
- std::numeric_limits<size_t>::max());
+ efi_status = m_client->set_var_check_property(m_common_guid, var_name_1, check_property,
+ std::numeric_limits<size_t>::max());
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
TEST(SmmVariableAttackTests, getCheckPropertyWithOversizeName)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"varibale_1";
-
VAR_CHECK_VARIABLE_PROPERTY check_property;
- efi_status = m_client->get_var_check_property(
- m_common_guid,
- var_name,
- check_property,
- (var_name.size() + 1) * sizeof(int16_t) + 1);
+ efi_status = m_client->get_var_check_property(m_common_guid, var_name_1, check_property,
+ (var_name_1.size() + 1) * sizeof(int16_t) + 1);
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
TEST(SmmVariableAttackTests, getCheckPropertyWithMaxSizeName)
{
efi_status_t efi_status = EFI_SUCCESS;
- std::wstring var_name = L"varibale_1";
VAR_CHECK_VARIABLE_PROPERTY check_property;
- efi_status = m_client->get_var_check_property(
- m_common_guid,
- var_name,
- check_property,
- std::numeric_limits<size_t>::max());
+ efi_status = m_client->get_var_check_property(m_common_guid, var_name_1, check_property,
+ std::numeric_limits<size_t>::max());
UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
}
diff --git a/components/service/uefi/smm_variable/test/service/smm_variable_service_tests.cpp b/components/service/uefi/smm_variable/test/service/smm_variable_service_tests.cpp
new file mode 100644
index 000000000..e82a90c37
--- /dev/null
+++ b/components/service/uefi/smm_variable/test/service/smm_variable_service_tests.cpp
@@ -0,0 +1,972 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <codecvt>
+#include <cstring>
+#include <locale>
+#include <sstream>
+
+#include "util.h"
+
+#if defined(UEFI_AUTH_VAR)
+#include "auth_vectors/KEK.h"
+#include "auth_vectors/KEK_delete.h"
+#include "auth_vectors/PK1.h"
+#include "auth_vectors/PK1_delete.h"
+#include "auth_vectors/PK2.h"
+#include "auth_vectors/PK2_delete.h"
+#include "auth_vectors/PK3.h"
+#include "auth_vectors/db1.h"
+#include "auth_vectors/db2.h"
+#include "auth_vectors/var.h"
+#include "auth_vectors/var_data.h"
+#include "auth_vectors/var_delete.h"
+#endif
+#include "common/uuid/uuid.h"
+#include "protocols/rpc/common/packed-c/encoding.h"
+#include "service/uefi/smm_variable/client/cpp/smm_variable_client.h"
+#include "service_locator.h"
+
+/*
+ * Service-level tests for the smm-variable service.
+ */
+TEST_GROUP(SmmVariableServiceTests)
+{
+ void setup()
+ {
+ m_rpc_session = NULL;
+ m_service_context = NULL;
+
+ service_locator_init();
+
+ m_service_context = service_locator_query("sn:trustedfirmware.org:smm-variable:0");
+ CHECK_TRUE(m_service_context);
+
+ m_rpc_session = service_context_open(m_service_context);
+ CHECK_TRUE(m_rpc_session);
+
+ m_client = new smm_variable_client(m_rpc_session);
+ }
+
+ void teardown()
+ {
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, cleanupPersistentStore());
+
+ delete m_client;
+ m_client = NULL;
+
+ if (m_service_context) {
+ if (m_rpc_session) {
+ service_context_close(m_service_context, m_rpc_session);
+ m_rpc_session = NULL;
+ }
+
+ service_context_relinquish(m_service_context);
+ m_service_context = NULL;
+ }
+ }
+
+ std::u16string to_variable_name(const char16_t *string)
+ {
+ std::u16string var_name(string);
+ var_name.push_back(0);
+
+ return var_name;
+ }
+
+ std::string guid_to_string(EFI_GUID *guid)
+ {
+ struct uuid_canonical canonical_uuid;
+
+ /* EFI_GUID is similar to the UUID octet structure */
+ uuid_canonical_from_guid_octets(&canonical_uuid, (const struct uuid_octets *)guid);
+
+ return std::string(canonical_uuid.characters);
+ }
+
+ /*
+ * Adds a UEFI variable in a formatted way to a buffer. e.g:
+ * name: Bob
+ * guid: {0x01234567, 0x89ab, 0xCDEF, {0x1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }}
+ */
+ void addVariableToMessage(std::u16string &var_name, EFI_GUID *guid, std::string &out)
+ {
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+
+ /* Remove null terminator! */
+ out += "\tname: ";
+ out += (convert.to_bytes(var_name)).substr(0, var_name.size() - 1);
+ out += "\n\tguid: ";
+ out += guid_to_string(guid);
+ out += "\n";
+ }
+
+ bool isVariableUncleanable(std::u16string &var_name)
+ {
+ for(std::u16string* element : m_non_rm_vars) {
+ if (!var_name.compare(*element))
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Clear all the removable variables from the persistent store. */
+ efi_status_t cleanupPersistentStore()
+ {
+ std::string error_message;
+ std::u16string var_name = to_variable_name(u"");
+ std::string get_data;
+ EFI_GUID guid;
+ efi_status_t status;
+
+ memset(&guid, 0, sizeof(guid));
+
+#if defined(UEFI_AUTH_VAR)
+
+ /* Remove PK if exists */
+ status = m_client->get_variable(m_global_guid, u"PK", get_data);
+
+ if (status == EFI_SUCCESS) {
+ /*
+ * PK must be cleared to disable authentication so other
+ * variables can be deleted easily. Return value is not
+ * checked, because if there is no PK in the store it
+ * will not be found.
+ */
+ status = m_client->set_variable(m_global_guid, u"PK", PK1_delete_auth,
+ sizeof(PK1_delete_auth),
+ m_authentication_common_attributes);
+
+ if (status)
+ FAIL("Cannot remove PK at cleanup!");
+ }
+
+ /*
+ * Note:
+ * If a test fills PK with data not removable by PK1_delete_auth request
+ * the proper request has to be added here or at the end of the specific test!
+ */
+#endif
+
+ do {
+ status = m_client->get_next_variable_name(guid, var_name);
+
+ /* There are no more variables in the persistent store */
+ if (status == EFI_NOT_FOUND) {
+ status = EFI_SUCCESS;
+ break;
+ } else if (status != EFI_SUCCESS) {
+ addVariableToMessage(var_name, &guid, error_message);
+ break;
+ }
+
+ /* Skip variables that cannot be deleted */
+ if (isVariableUncleanable(var_name))
+ continue;
+
+ status = m_client->remove_variable(guid, var_name);
+
+#if defined(UEFI_AUTH_VAR)
+ /*
+ * Authenticated variables can be removed only with authentication
+ * header. If the variable could not be removed with a normal call,
+ * try again with an empty header.
+ */
+ if (status) {
+ status = m_client->set_variable(guid, var_name, m_empty_auth_header,
+ sizeof(m_empty_auth_header),
+ m_authentication_common_attributes);
+ }
+#endif
+ if (status) {
+ addVariableToMessage(var_name, &guid, error_message);
+ break;
+ }
+
+ /*
+ * If the variable was successfully removed the fields are cleared so
+ * the iteration will start again from the first available variable.
+ * If the remove is unsuccessful (for example the variable is not
+ * accessible from runtime or read only) the fields are kept so the
+ * iteration searches for the next one. This case there could be a
+ * combination when this function tries to remove non-removable
+ * variables multiple times.
+ * */
+ if (status == EFI_SUCCESS) {
+ var_name = to_variable_name(u"");
+ memset(&guid, 0, sizeof(guid));
+ }
+
+ } while (1);
+
+ if (error_message.length() != 0) {
+ error_message.insert(0, "Could not remove variable: \n");
+ UT_PRINT(error_message.c_str());
+ }
+
+ return status;
+ }
+
+ smm_variable_client *m_client;
+ struct rpc_caller_session *m_rpc_session;
+ struct service_context *m_service_context;
+
+ /*
+ * List of the variables which cannot be deleted.
+ * E.g read-only ones or those that have boot only access
+ */
+ std::u16string m_ro_variable = to_variable_name(u"ro_variable");
+ std::u16string m_boot_finished_var_name = to_variable_name(u"finished");
+
+ /* Cleanup skips these variables */
+ std::vector<std::u16string *> m_non_rm_vars{ &m_ro_variable, &m_boot_finished_var_name };
+
+ EFI_GUID m_common_guid = { 0x01234567,
+ 0x89ab,
+ 0xCDEF,
+ { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
+
+#if defined(UEFI_AUTH_VAR)
+ EFI_GUID m_global_guid = { 0x8BE4DF61,
+ 0x93CA,
+ 0x11d2,
+ { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } };
+ EFI_GUID m_security_database_guid = { 0xd719b2cb,
+ 0x3d3a,
+ 0x4596,
+ { 0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f } };
+ uint32_t m_authentication_common_attributes =
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ uint8_t m_empty_auth_header[40] = { /* TimeStamp */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* dwLength = header size - sizeof (TimeStamp) */
+ 24, 0, 0, 0,
+ /* wRevision = WIN_CERT_CURRENT_VERSION */
+ 0x00, 0x02,
+ /* wCertificateType = WIN_CERT_TYPE_EFI_GUID */
+ 0xF1, 0x0E,
+ /* CertType = EFI_CERT_TYPE_PKCS7_GUID */
+ 0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, 0x8a,
+ 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7
+ };
+#endif
+};
+
+TEST(SmmVariableServiceTests, setAndGet)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+ const char16_t var_name[] = u"test_variable";
+ std::string set_data = "UEFI variable data string";
+ std::string get_data;
+
+ efi_status = m_client->set_variable(m_common_guid, var_name, set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
+ STRCMP_EQUAL(set_data.c_str(), get_data.c_str());
+
+ /* Extend the variable using an append write */
+ std::string append_data = " values added with append write";
+
+ efi_status = m_client->set_variable(m_common_guid, var_name, append_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_APPEND_WRITE);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ std::string appended_data = set_data + append_data;
+
+ /* Expect the append write operation to have extended the variable */
+ UNSIGNED_LONGLONGS_EQUAL(appended_data.size(), get_data.size());
+ STRCMP_EQUAL(appended_data.c_str(), get_data.c_str());
+
+ /* Expect remove to be permitted */
+ efi_status = m_client->remove_variable(m_common_guid, var_name);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
+}
+
+TEST(SmmVariableServiceTests, setAndGetNv)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+ const char16_t var_name[] = u"an NV test_variable";
+ std::string set_data = "Another UEFI variable data string";
+ std::string get_data;
+
+ efi_status = m_client->set_variable(m_common_guid, var_name, set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
+ STRCMP_EQUAL(set_data.c_str(), get_data.c_str());
+
+ /* Extend the variable using an append write */
+ std::string append_data = " values added with append write";
+
+ efi_status = m_client->set_variable(
+ m_common_guid, var_name, append_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_APPEND_WRITE);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ std::string appended_data = set_data + append_data;
+
+ /* Expect the append write operation to have extended the variable */
+ UNSIGNED_LONGLONGS_EQUAL(appended_data.size(), get_data.size());
+ STRCMP_EQUAL(appended_data.c_str(), get_data.c_str());
+
+ /* Expect remove to be permitted */
+ efi_status = m_client->remove_variable(m_common_guid, var_name);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
+}
+
+TEST(SmmVariableServiceTests, getVarSize)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+ const char16_t var_name[] = u"test_variable";
+ std::string set_data = "UEFI variable data string";
+ std::string get_data;
+
+ efi_status = m_client->set_variable(m_common_guid, var_name, set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Get with the data size set to zero. This is the standard way
+ * to discover the variable size. */
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data, 0, 0);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_BUFFER_TOO_SMALL, efi_status);
+ UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
+
+ /* Expect remove to be permitted */
+ efi_status = m_client->remove_variable(m_common_guid, var_name);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
+}
+
+TEST(SmmVariableServiceTests, getVarSizeNv)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+ const char16_t var_name[] = u"test_variable";
+ std::string set_data = "UEFI variable data string";
+ std::string get_data;
+
+ efi_status = m_client->set_variable(m_common_guid, var_name, set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Get with the data size set to zero. This is the standard way
+ * to discover the variable size. */
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data, 0, 0);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_BUFFER_TOO_SMALL, efi_status);
+ UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
+
+ /* Expect remove to be permitted */
+ efi_status = m_client->remove_variable(m_common_guid, var_name);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->get_variable(m_common_guid, var_name, get_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
+}
+
+/* This test makes the irreversible transition from boot to runtime
+ * state, leaving a variable that can't be removed. To prevent this from
+ * breaking the variable enumeration test, this test is called from
+ * the enumeration test to guarantee the order.
+ */
+TEST(SmmVariableServiceTests, runtimeStateAccessControl)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+
+ std::string boot_finished_var_data = "Set after bootstate is finished";
+ const char16_t boot_var_name[] = u"a boot variable";
+ std::string boot_set_data = "Only accessible during boot";
+ const char16_t runtime_var_name[] = u"a runtime variable";
+ std::string runtime_set_data = "Only accessible during runtime";
+ std::string get_data;
+
+ efi_status = m_client->get_variable(m_common_guid, m_boot_finished_var_name, get_data);
+ if (efi_status == EFI_SUCCESS) {
+ UT_PRINT("runtimeStateAccessControl testcase can only run once per boot cycle. "
+ "It exits boot state, blocking access to the added boot variables, "
+ "so the test is skipped for now.");
+ return;
+ }
+
+ /* The variable should be successfully found or NOT_FOUND. Other values are related to errors */
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
+
+ /* Add variables with runtime state access control */
+ efi_status = m_client->set_variable(m_common_guid, boot_var_name, boot_set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status =
+ m_client->set_variable(m_common_guid, runtime_var_name, runtime_set_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Expect access to boot variable to be permitted */
+ efi_status = m_client->get_variable(m_common_guid, boot_var_name, get_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+ UNSIGNED_LONGS_EQUAL(boot_set_data.size(), get_data.size());
+ STRCMP_EQUAL(boot_set_data.c_str(), get_data.c_str());
+
+ /* Expect access to the runtime variable to also be permitted during boot */
+ efi_status = m_client->get_variable(m_common_guid, runtime_var_name, get_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Exit boot service - access should no longer be permitted */
+ efi_status = m_client->exit_boot_service();
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Access to the boot variable should now be forbidden */
+ efi_status = m_client->get_variable(m_common_guid, boot_var_name, get_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
+
+ /* Expect access to the runtime variable should still be permitted */
+ efi_status = m_client->get_variable(m_common_guid, runtime_var_name, get_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+ UNSIGNED_LONGS_EQUAL(runtime_set_data.size(), get_data.size());
+ STRCMP_EQUAL(runtime_set_data.c_str(), get_data.c_str());
+
+ /* Expect removing boot variable to be forbidden */
+ efi_status = m_client->remove_variable(m_common_guid, boot_var_name);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
+
+ /* Expect removing runtime variable to be permitted */
+ efi_status = m_client->remove_variable(m_common_guid, runtime_var_name);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Set a non-volatile read-only variable marking the end of the boot phase */
+ efi_status = m_client->set_variable(
+ m_common_guid, m_boot_finished_var_name, boot_finished_var_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Apply a check to constrain to Read Only */
+ VAR_CHECK_VARIABLE_PROPERTY check_property;
+ check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ check_property.Attributes = 0;
+ check_property.Property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ check_property.MinSize = 0;
+ check_property.MaxSize = 100;
+
+ efi_status = m_client->set_var_check_property(m_common_guid, m_boot_finished_var_name,
+ check_property);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+}
+
+/* This test leaves a read-only variable in the store */
+TEST(SmmVariableServiceTests, readOnlyConstraint)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+
+ std::string set_data = "A read only variable";
+ std::string get_data;
+
+ /* Only add the read only variable if it is not already created */
+ efi_status = m_client->get_variable(m_common_guid, m_ro_variable, get_data);
+
+ if (efi_status != EFI_SUCCESS) {
+ /* Add a variable to the store */
+ efi_status = m_client->set_variable(m_common_guid, m_ro_variable, set_data,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Apply a check to constrain to Read Only */
+ VAR_CHECK_VARIABLE_PROPERTY check_property;
+ check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ check_property.Attributes = 0;
+ check_property.Property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ check_property.MinSize = 0;
+ check_property.MaxSize = 100;
+
+ efi_status = m_client->set_var_check_property(m_common_guid, m_ro_variable,
+ check_property);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Read back the check property constraint and expect it to match the set value */
+ VAR_CHECK_VARIABLE_PROPERTY got_check_property;
+
+ efi_status = m_client->get_var_check_property(m_common_guid, m_ro_variable,
+ got_check_property);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ UNSIGNED_LONGS_EQUAL(check_property.Revision, got_check_property.Revision);
+ UNSIGNED_LONGS_EQUAL(check_property.Attributes, got_check_property.Attributes);
+ UNSIGNED_LONGS_EQUAL(check_property.Property, got_check_property.Property);
+ UNSIGNED_LONGS_EQUAL(check_property.MinSize, got_check_property.MinSize);
+ UNSIGNED_LONGS_EQUAL(check_property.MaxSize, got_check_property.MaxSize);
+ } else {
+ UT_PRINT("Read-only variable already exists");
+ }
+
+ /* Attempt to modify variable */
+ efi_status = m_client->set_variable(
+ m_common_guid, m_ro_variable, std::string("Different variable data"),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_WRITE_PROTECTED, efi_status);
+
+ /* Expect to still be able to read variable */
+ efi_status = m_client->get_variable(m_common_guid, m_ro_variable, get_data);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Variable value should be unmodified */
+ UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
+ STRCMP_EQUAL(set_data.c_str(), get_data.c_str());
+}
+
+TEST(SmmVariableServiceTests, enumerateStoreContents)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+ std::string get_data;
+
+ /* Query information about the variable store */
+ size_t nv_max_variable_storage_size = 0;
+ size_t nv_max_variable_size = 0;
+ size_t nv_remaining_variable_storage_size = 0;
+
+ efi_status = m_client->query_variable_info(EFI_VARIABLE_NON_VOLATILE,
+ &nv_max_variable_storage_size,
+ &nv_remaining_variable_storage_size,
+ &nv_max_variable_size);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ size_t v_max_variable_storage_size = 0;
+ size_t v_max_variable_size = 0;
+ size_t v_remaining_variable_storage_size = 0;
+
+ efi_status = m_client->query_variable_info(0, &v_max_variable_storage_size,
+ &v_remaining_variable_storage_size,
+ &v_max_variable_size);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Add some variables to the store */
+ std::u16string var_name_1 = to_variable_name(u"variable_1");
+ std::u16string var_name_2 = to_variable_name(u"variable_2");
+ std::u16string var_name_3 = to_variable_name(u"variable_3");
+ std::string set_data = "Some variable data";
+
+ efi_status = m_client->set_variable(m_common_guid, var_name_1, set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->set_variable(m_common_guid, var_name_2, set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->set_variable(m_common_guid, var_name_3, set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Query variable info again and check it's as expected */
+ size_t max_variable_storage_size = 0;
+ size_t max_variable_size = 0;
+ size_t remaining_variable_storage_size = 0;
+
+ /* Check non-volatile - two variables have been added */
+ efi_status =
+ m_client->query_variable_info(EFI_VARIABLE_NON_VOLATILE, &max_variable_storage_size,
+ &remaining_variable_storage_size, &max_variable_size);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+ UNSIGNED_LONGLONGS_EQUAL((nv_remaining_variable_storage_size - set_data.size() * 2),
+ remaining_variable_storage_size);
+
+ /* Check volatile - one variable has been added */
+ efi_status = m_client->query_variable_info(0, &max_variable_storage_size,
+ &remaining_variable_storage_size,
+ &max_variable_size);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+ UNSIGNED_LONGLONGS_EQUAL((v_remaining_variable_storage_size - set_data.size() * 1),
+ remaining_variable_storage_size);
+
+ /*
+ * Enumerate store contents. We know nothing about the original state of the store
+ * (there can be read only variables from previous test runs) so our new variables
+ * are added to a list and we check if all of them are added by iterating through
+ * all elements of the store.
+ */
+ std::u16string var_name = to_variable_name(u"");
+ EFI_GUID guid;
+ memset(&guid, 0, sizeof(guid));
+
+ std::u16string *expected_variables[] = { &var_name_1, &var_name_2, &var_name_3 };
+
+ do {
+ efi_status = m_client->get_next_variable_name(guid, var_name);
+ if (efi_status != EFI_SUCCESS)
+ break;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(expected_variables); i++) {
+ /* Skipp NULL elements*/
+ if (!expected_variables[i])
+ continue;
+ /* Check if the found variable is in the expected list */
+ if (!var_name.compare(*expected_variables[i])) {
+ if ((*expected_variables[i]).size() == var_name.size())
+ expected_variables[i] = NULL;
+ }
+ }
+ } while (1);
+
+ // Fail if sore content enumeration failed.
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, efi_status);
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(expected_variables); i++) {
+ if (expected_variables[i])
+ FAIL("Not all variables were found in the store");
+ }
+
+ /* Expect to be able to remove all variables */
+ efi_status = m_client->remove_variable(m_common_guid, var_name_1);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->remove_variable(m_common_guid, var_name_2);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ efi_status = m_client->remove_variable(m_common_guid, var_name_3);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+}
+
+TEST(SmmVariableServiceTests, setSizeConstraint)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+ const char16_t var_name_1[] = u"size_limited_variable";
+ std::string set_data = "Initial value";
+
+ /* Add a variable to the store */
+ efi_status = m_client->set_variable(m_common_guid, var_name_1, set_data,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Apply a check to constrain the variable size */
+ VAR_CHECK_VARIABLE_PROPERTY check_property;
+ check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ check_property.Attributes = 0;
+ check_property.Property = 0;
+ check_property.MinSize = 0;
+ check_property.MaxSize = 20;
+
+ efi_status = m_client->set_var_check_property(m_common_guid, var_name_1, check_property);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Attempt to set value to a size that exceeds the MaxSize constraint */
+ efi_status = m_client->set_variable(
+ m_common_guid, var_name_1,
+ std::string("A data value that exceeds the MaxSize constraint"),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
+
+ /* But setting a value that's within the constraints should work */
+ efi_status = m_client->set_variable(m_common_guid, var_name_1, std::string("Small value"),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Removing should be allowed though */
+ efi_status = m_client->remove_variable(m_common_guid, var_name_1);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
+ /* Although the variable has been removed, the constraint should
+ * still be set.
+ */
+ efi_status = m_client->set_variable(
+ m_common_guid, var_name_1,
+ std::string("Another try to set a value that exceeds the MaxSize constraint"),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, efi_status);
+}
+
+TEST(SmmVariableServiceTests, checkMaxVariablePayload)
+{
+ efi_status_t efi_status = EFI_SUCCESS;
+ size_t max_payload_size = 0;
+
+ /* Expect to read a reasonable size for the variable payload */
+ efi_status = m_client->get_payload_size(max_payload_size);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+ CHECK_TRUE(max_payload_size >= 1024);
+ CHECK_TRUE(max_payload_size <= 64 * 1024);
+}
+
+#if defined(UEFI_AUTH_VAR)
+TEST(SmmVariableServiceTests, authenticationDisabled)
+{
+ efi_status_t status;
+ std::string read_data;
+
+ /* Without PK the authentication is disabled so each variable are writable, even in wrong order */
+ status = m_client->set_variable(m_common_guid, u"var", VAR_auth, sizeof(VAR_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = m_client->get_variable(m_common_guid, u"var", read_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(var_data_txt_len, read_data.size());
+ MEMCMP_EQUAL(var_data_txt, read_data.c_str(), var_data_txt_len);
+
+ status = m_client->set_variable(m_security_database_guid, u"db", (uint8_t *)DB1_auth,
+ sizeof(DB1_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = m_client->set_variable(m_global_guid, u"KEK", (uint8_t *)KEK_auth,
+ sizeof(KEK_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+}
+
+TEST(SmmVariableServiceTests, authenticationSetAllKeys)
+{
+ efi_status_t status;
+ std::string read_data;
+
+ /* Enable authentication via setting PK */
+ status = m_client->set_variable(m_global_guid, u"PK", PK1_auth, sizeof(PK1_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Try setting db1 and custom variable without KEK */
+ status = m_client->set_variable(m_security_database_guid, u"db", DB1_auth,
+ sizeof(DB1_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ status = m_client->set_variable(m_common_guid, u"var", VAR_auth, sizeof(VAR_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* Set db2 that was signed by OK */
+ status = m_client->set_variable(m_security_database_guid, u"db", DB2_auth,
+ sizeof(DB2_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Set KEK */
+ status = m_client->set_variable(m_global_guid, u"KEK", KEK_auth, sizeof(KEK_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Try setting custom variable with wrong db */
+ status = m_client->set_variable(m_common_guid, u"var", VAR_auth, sizeof(VAR_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* Set db and var and then overwrite var */
+ status = m_client->set_variable(m_security_database_guid, u"db", DB1_auth,
+ sizeof(DB1_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* The variable is not yet set */
+ status = m_client->get_variable(m_common_guid, u"var", read_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+
+ /* Set variable */
+ status = m_client->set_variable(m_common_guid, u"var", VAR_auth, sizeof(VAR_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Get and validate variable value */
+ status = m_client->get_variable(m_common_guid, u"var", read_data);
+ UNSIGNED_LONGS_EQUAL(var_data_txt_len, read_data.size());
+ MEMCMP_EQUAL(var_data_txt, read_data.c_str(), var_data_txt_len);
+
+ /* Set variable with empty payload */
+ status = m_client->set_variable(m_common_guid, u"var", VAR_delete_auth,
+ sizeof(VAR_delete_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Check if it doesn't exist */
+ status = m_client->get_variable(m_common_guid, u"var", read_data);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
+}
+
+TEST(SmmVariableServiceTests, authenticationDelete)
+{
+ efi_status_t status;
+
+ /* Enable authentication via setting PK */
+ status = m_client->set_variable(m_global_guid, u"PK", PK1_auth, sizeof(PK1_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Set KEK and db */
+ status = m_client->set_variable(m_global_guid, u"KEK", KEK_auth, sizeof(KEK_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = m_client->set_variable(m_security_database_guid, u"db", DB1_auth,
+ sizeof(DB1_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Remove KEK and try overwriting db with a valid request which should fail without KEK */
+ status = m_client->set_variable(m_global_guid, u"KEK", KEK_delete_auth,
+ sizeof(KEK_delete_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = m_client->set_variable(m_security_database_guid, u"db", DB1_auth,
+ sizeof(DB1_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* Although db was not overwritten the original value is still available to verify the custom variable */
+ status = m_client->set_variable(m_common_guid, u"var", VAR_auth, sizeof(VAR_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Try removing PK with an incorrect, non-authenticated delete request */
+ status = m_client->remove_variable(m_global_guid, u"PK");
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* Remove PK so now db can be overwritten, because authentication is disabled */
+ status = m_client->set_variable(m_global_guid, u"PK", PK1_delete_auth,
+ sizeof(PK1_delete_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = m_client->set_variable(m_security_database_guid, u"db", DB1_auth,
+ sizeof(DB1_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+}
+
+TEST(SmmVariableServiceTests, authenticationChangePK)
+{
+ efi_status_t status;
+
+ /* Enable authentication via setting the platform key */
+ status = m_client->set_variable(m_global_guid, u"PK", PK1_auth, sizeof(PK1_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* PK3 can not be set, because it is not signed by the current platform key */
+ status = m_client->set_variable(m_global_guid, u"PK", PK3_auth, sizeof(PK3_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* PK2 can be set, because it is signed by the current platform key */
+ status = m_client->set_variable(m_global_guid, u"PK", PK2_auth, sizeof(PK2_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Clear PK2 */
+ status = m_client->set_variable(m_global_guid, u"PK", PK2_delete_auth,
+ sizeof(PK2_delete_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+}
+
+TEST(SmmVariableServiceTests, authenticationSignatureVerifyFailure)
+{
+ efi_status_t status;
+
+ uint32_t dwLength = KEK_auth[16] | KEK_auth[17] << 8 | KEK_auth[18] << 16 |
+ KEK_auth[19] << 24;
+
+ /* Find error injection points in signature, public key and timestamp fields */
+ uint8_t *signature = &KEK_auth[dwLength + 16 - 1];
+ uint8_t *public_key = &KEK_auth[sizeof(KEK_auth) - 1];
+ uint8_t *timestamp = &KEK_auth[0];
+
+ /* Enable authentication via setting PK */
+ status = m_client->set_variable(m_global_guid, u"PK", PK1_auth, sizeof(PK1_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Try setting KEK with wrong signature */
+ *signature = ~(*signature);
+ status = m_client->set_variable(m_global_guid, u"KEK", KEK_auth, sizeof(KEK_auth),
+ m_authentication_common_attributes);
+ *signature = ~(*signature);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* Try setting KEK with wrong public key */
+ *public_key = ~(*public_key);
+ status = m_client->set_variable(m_global_guid, u"KEK", KEK_auth, sizeof(KEK_auth),
+ m_authentication_common_attributes);
+ *public_key = ~(*public_key);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* Try setting KEK with wrong timestamp that results in wrong hash */
+ *timestamp = ~(*timestamp);
+ status = m_client->set_variable(m_global_guid, u"KEK", KEK_auth, sizeof(KEK_auth),
+ m_authentication_common_attributes);
+ *timestamp = ~(*timestamp);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* db can not be set, because KEK was not added to the store */
+ status = m_client->set_variable(m_security_database_guid, u"db", DB1_auth,
+ sizeof(DB1_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SECURITY_VIOLATION, status);
+
+ /* Set correct KEK */
+ status = m_client->set_variable(m_global_guid, u"KEK", KEK_auth, sizeof(KEK_auth),
+ m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Set db */
+ status = m_client->set_variable(m_security_database_guid, u"db", DB1_auth,
+ sizeof(DB1_auth), m_authentication_common_attributes);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+}
+#endif
diff --git a/deployments/attestation/attestation.cmake b/deployments/attestation/attestation.cmake
new file mode 100644
index 000000000..cf00a33cf
--- /dev/null
+++ b/deployments/attestation/attestation.cmake
@@ -0,0 +1,44 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "attestation"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/tlv"
+ "components/common/endian"
+ "components/rpc/common/interface"
+ "components/service/common/include"
+ "components/service/common/provider"
+ "components/service/attestation/include"
+ "components/service/attestation/claims"
+ "components/service/attestation/reporter/local"
+ "components/service/attestation/reporter/eat"
+ "components/service/attestation/key_mngr/local"
+ "components/service/attestation/provider"
+ "components/service/attestation/provider/serializer/packed-c"
+ "protocols/rpc/common/packed-c"
+)
+
+#-------------------------------------------------------------------------------
+# Components used from external projects
+#
+#-------------------------------------------------------------------------------
+
+# Qcbor
+include(${TS_ROOT}/external/qcbor/qcbor.cmake)
+target_link_libraries(attestation PRIVATE qcbor)
+
+# t_cose
+include(${TS_ROOT}/external/t_cose/t_cose.cmake)
+target_link_libraries(attestation PRIVATE t_cose)
+
+#################################################################
+
+target_include_directories(attestation PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
diff --git a/deployments/attestation/config/default-opteesp/CMakeLists.txt b/deployments/attestation/config/default-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..58ecb3412
--- /dev/null
+++ b/deployments/attestation/config/default-opteesp/CMakeLists.txt
@@ -0,0 +1,97 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the attestation deployment for opteesp
+#
+# Builds the attestation service provider for running in an SEL0 secure partition
+# hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(attestation)
+target_include_directories(attestation PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "a1baf155-8876-4695-8f7c-54955e8db974")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "ATT" CACHE STRING "Trace prefix")
+
+target_include_directories(attestation PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Default deployment specific configuration
+#
+#-------------------------------------------------------------------------------
+set(TS_NO_FLOAT_HW ON)
+
+#-------------------------------------------------------------------------------
+# Deployment specific components
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "attestation"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/attestation_sp.cmake REQUIRED)
+include(../../infra/tpm-eventlog-psa.cmake REQUIRED)
+include(../../attestation.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "attestation")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(attestation PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(attestation PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+#TODO: api headers
+
+install(TARGETS attestation
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+get_property(_PROTO_FILES TARGET attestation PROPERTY PROTOBUF_FILES)
+install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "attestation"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_attestation.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/attestation/opteesp/default_attestation.dts.in b/deployments/attestation/config/default-opteesp/default_attestation.dts.in
index 1a7439742..3a2ac76c9 100644
--- a/deployments/attestation/opteesp/default_attestation.dts.in
+++ b/deployments/attestation/config/default-opteesp/default_attestation.dts.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,14 +15,23 @@
exception-level = <1>; /* S-EL0 */
execution-state = <0>; /* AArch64 */
xlat-granule = <0>; /* 4KiB */
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
boot-params {
compatible = "arm,ffa-manifest-boot-params";
+ /* Legacy node to keep compatibility with psa-development SPMC. */
event-log {
param = "EVENT_LOG"; /* The init parameter name */
tag = "arm,event-log"; /* Object identifier */
};
};
+
+ tpm_event_log {
+ compatible = "arm,tpm_event_log";
+ tpm_event_log_addr = <0x0 0x0>;
+ tpm_event_log_size = <0x0>;
+ };
};
diff --git a/deployments/attestation/config/default-opteesp/optee_sp_user_defines.h b/deployments/attestation/config/default-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..ebc7dada8
--- /dev/null
+++ b/deployments/attestation/config/default-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/attestation/config/default-sp/CMakeLists.txt b/deployments/attestation/config/default-sp/CMakeLists.txt
new file mode 100644
index 000000000..cdcbdcd71
--- /dev/null
+++ b/deployments/attestation/config/default-sp/CMakeLists.txt
@@ -0,0 +1,97 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the attestation deployment for generic sp
+# environment.
+#
+# Builds the attestation service provider for running in an SEL0 secure
+# partition hosted by any SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(attestation)
+target_include_directories(attestation PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_NAME "attestation")
+set(SP_BIN_UUID_CANON "a1baf155-8876-4695-8f7c-54955e8db974")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(TRACE_PREFIX "ATT" CACHE STRING "Trace prefix")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+
+#-------------------------------------------------------------------------------
+# Default deployment specific configuration
+#
+#-------------------------------------------------------------------------------
+set(TS_NO_FLOAT_HW ON)
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the sp environment.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "attestation"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+include(../../env/commonsp/attestation_sp.cmake REQUIRED)
+include(../../infra/tpm-eventlog-psa.cmake REQUIRED)
+include(../../attestation.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "attestation")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(attestation PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(attestation PRIVATE
+ -std=c99
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET attestation NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET attestation NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS attestation
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/attestation/config/default-sp/default_attestation.dts.in b/deployments/attestation/config/default-sp/default_attestation.dts.in
new file mode 100644
index 000000000..2e16f7ed9
--- /dev/null
+++ b/deployments/attestation/config/default-sp/default_attestation.dts.in
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "Attestation";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+
+ boot-params {
+ compatible = "arm,ffa-manifest-boot-params";
+
+ event-log {
+ param = "EVENT_LOG"; /* The init parameter name */
+ tag = "arm,event-log"; /* Object identifier */
+ };
+ };
+
+ tpm_event_log {
+ compatible = "arm,tpm_event_log";
+ tpm_event_log_addr = <0x0 0x0>;
+ tpm_event_log_size = <0x0>;
+ };
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ #include "@EXPORT_DTS_MEM_REGIONS@"
+ };
+};
diff --git a/deployments/attestation/env/commonsp/attestation_sp.c b/deployments/attestation/env/commonsp/attestation_sp.c
new file mode 100644
index 000000000..0ed3f6503
--- /dev/null
+++ b/deployments/attestation/env/commonsp/attestation_sp.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h"
+#include "components/rpc/ts_rpc/caller/sp/ts_rpc_caller_sp.h"
+#include "components/rpc/common/caller/rpc_caller_session.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "config/ramstore/config_ramstore.h"
+#include "config/loader/sp/sp_config_loader.h"
+#include "service/attestation/provider/attest_provider.h"
+#include "service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h"
+#include "service/attestation/claims/claims_register.h"
+#include "service/attestation/claims/sources/event_log/event_log_claim_source.h"
+#include "service/attestation/claims/sources/boot_seed_generator/boot_seed_generator.h"
+#include "service/attestation/claims/sources/null_lifecycle/null_lifecycle_claim_source.h"
+#include "service/attestation/claims/sources/instance_id/instance_id_claim_source.h"
+#include "service/attestation/claims/sources/implementation_id/implementation_id_claim_source.h"
+#include "service/attestation/key_mngr/local/local_attest_key_mngr.h"
+#include "service/crypto/client/psa/psa_crypto_client.h"
+#include "service_locator.h"
+#include "psa/crypto.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+
+static bool sp_init(uint16_t *own_sp_id);
+static bool locate_crypto_service(void);
+
+void __noreturn sp_main(union ffa_boot_info *boot_info)
+{
+ /* Service provider objects */
+ struct attest_provider attest_provider = { 0 };
+ struct rpc_service_interface *attest_iface = NULL;
+ struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
+ struct sp_msg req_msg = { 0 };
+ struct sp_msg resp_msg = { 0 };
+ uint16_t own_id = 0;
+ sp_result result = SP_RESULT_INTERNAL_ERROR;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Claim source objects */
+ struct claim_source *claim_source = NULL;
+ struct event_log_claim_source event_log_claim_source = { 0 };
+ struct boot_seed_generator boot_seed_claim_source = { 0 };
+ struct null_lifecycle_claim_source lifecycle_claim_source = { 0 };
+ struct instance_id_claim_source instance_id_claim_source = { 0 };
+ struct implementation_id_claim_source implementation_id_claim_source = { 0 };
+
+ /*********************************************************
+ * Boot phase
+ *********************************************************/
+ if (!sp_init(&own_id)) {
+ EMSG("Failed to init SP");
+ goto fatal_error;
+ }
+
+ config_ramstore_init();
+
+ if (!sp_config_load(boot_info)) {
+ EMSG("Failed to load SP config");
+ goto fatal_error;
+ }
+
+ /**
+ * Locate crypto service endpoint and establish RPC session
+ */
+ if (!locate_crypto_service()) {
+ EMSG("Failed to locate crypto service");
+ goto fatal_error;
+ }
+
+ /**
+ * Register claim sources for deployment
+ */
+ claims_register_init();
+
+ /* Boot measurement claim source */
+ claim_source = event_log_claim_source_init_from_config(&event_log_claim_source);
+ if (!claim_source) {
+ EMSG("Failed to claim event log source from config");
+ goto fatal_error;
+ }
+ claims_register_add_claim_source(CLAIM_CATEGORY_BOOT_MEASUREMENT, claim_source);
+
+ /* Boot seed claim source */
+ claim_source = boot_seed_generator_init(&boot_seed_claim_source);
+ if (!claim_source) {
+ EMSG("Failed to initialize boot seed generator");
+ goto fatal_error;
+ }
+ claims_register_add_claim_source(CLAIM_CATEGORY_DEVICE, claim_source);
+
+ /* Lifecycle state claim source */
+ claim_source = null_lifecycle_claim_source_init(&lifecycle_claim_source);
+ if (!claim_source) {
+ EMSG("Failed to initialize lifecycle state claim source");
+ goto fatal_error;
+ }
+ claims_register_add_claim_source(CLAIM_CATEGORY_DEVICE, claim_source);
+
+ /* Instance ID claim source */
+ claim_source = instance_id_claim_source_init(&instance_id_claim_source);
+ if (!claim_source) {
+ EMSG("Failed to initialize instance ID claim source");
+ goto fatal_error;
+ }
+ claims_register_add_claim_source(CLAIM_CATEGORY_DEVICE, claim_source);
+
+ /* Implementation ID claim source */
+ claim_source = implementation_id_claim_source_init(&implementation_id_claim_source,
+ "trustedfirmware.org.ts.attestation_sp");
+ if (!claim_source) {
+ EMSG("Failed to initialize implementation ID claim source");
+ goto fatal_error;
+ }
+ claims_register_add_claim_source(CLAIM_CATEGORY_DEVICE, claim_source);
+
+ /**
+ * Initialize the service provider
+ */
+ local_attest_key_mngr_init(LOCAL_ATTEST_KEY_MNGR_VOLATILE_IAK);
+ attest_iface = attest_provider_init(&attest_provider);
+ if (!attest_iface) {
+ EMSG("Failed to initialize attestation provider");
+ goto fatal_error;
+ }
+
+ attest_provider_register_serializer(&attest_provider,
+ packedc_attest_provider_serializer_instance());
+
+ rpc_status = ts_rpc_endpoint_sp_init(&rpc_endpoint, 1, 16);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to initialize RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, attest_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /*********************************************************
+ * End of boot phase
+ *********************************************************/
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ ts_rpc_endpoint_sp_receive(&rpc_endpoint, &req_msg, &resp_msg);
+
+ result = sp_msg_send_direct_resp(&resp_msg, &req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("Attestation SP error");
+ while (1) {}
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
+
+static bool sp_init(uint16_t *own_id)
+{
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ static uint8_t tx_buffer[4096] __aligned(4096);
+ static uint8_t rx_buffer[4096] __aligned(4096);
+
+ sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", sp_res);
+ return false;
+ }
+
+ sp_res = sp_discovery_own_id_get(own_id);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", sp_res);
+ return false;
+ }
+
+ return true;
+}
+
+bool locate_crypto_service(void)
+{
+ struct rpc_caller_session *session = NULL;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+
+ service_locator_init();
+
+ /* todo - add option to use configurable crypto service location */
+ struct service_context *crypto_service_context =
+ service_locator_query("sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0:0");
+
+ if (!crypto_service_context) {
+ EMSG("Service locator query failed");
+ return false;
+ }
+
+ session = service_context_open(crypto_service_context);
+ if (!session) {
+ EMSG("Failed to open crypto service context");
+ return false;
+ }
+
+ psa_status = psa_crypto_client_init(session);
+ if (psa_status != PSA_SUCCESS) {
+ EMSG("Failed to init PSA crypto client: %d", psa_status);
+ return false;
+ }
+
+ psa_status = psa_crypto_init();
+ if (psa_status != PSA_SUCCESS) {
+ EMSG("Failed to init PSA crypto: %d", psa_status);
+ return false;
+ }
+
+ return true;
+}
diff --git a/deployments/attestation/env/commonsp/attestation_sp.cmake b/deployments/attestation/env/commonsp/attestation_sp.cmake
new file mode 100644
index 000000000..fcef307ee
--- /dev/null
+++ b/deployments/attestation/env/commonsp/attestation_sp.cmake
@@ -0,0 +1,31 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the attestation service provider
+# within a secure partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for attestation sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "attestation"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/common/interface"
+ "components/rpc/common/endpoint"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/endpoint/sp"
+)
+
+target_sources(attestation PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/attestation_sp.c
+)
diff --git a/deployments/attestation/env/commonsp/attestation_sp.h b/deployments/attestation/env/commonsp/attestation_sp.h
new file mode 100644
index 000000000..89424aa2f
--- /dev/null
+++ b/deployments/attestation/env/commonsp/attestation_sp.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ATTESTATION_SP_H
+#define ATTESTATION_SP_H
+
+#endif /* ATTESTATION_SP_H */
diff --git a/deployments/attestation/infra/tpm-eventlog-psa.cmake b/deployments/attestation/infra/tpm-eventlog-psa.cmake
new file mode 100644
index 000000000..00150d4bd
--- /dev/null
+++ b/deployments/attestation/infra/tpm-eventlog-psa.cmake
@@ -0,0 +1,34 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Defines an infrastructure for the attestation service provider that uses a
+# a TPM eventlog to collect claims about the booted firmware. Uses PSA crypto
+# for EAT token signing.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "attestation"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/uuid"
+ "components/rpc/ts_rpc/caller/sp"
+ "components/rpc/common/caller"
+ "components/service/common/client"
+ "components/service/locator"
+ "components/service/locator/interface"
+ "components/service/locator/sp"
+ "components/service/locator/sp/ffa"
+ "components/service/attestation/claims/sources/boot_seed_generator"
+ "components/service/attestation/claims/sources/null_lifecycle"
+ "components/service/attestation/claims/sources/instance_id"
+ "components/service/attestation/claims/sources/implementation_id"
+ "components/service/attestation/claims/sources/event_log"
+ "components/service/attestation/claims/sources/event_log/mock"
+ "components/service/crypto/include"
+ "components/service/crypto/client/psa"
+)
diff --git a/deployments/attestation/opteesp/CMakeLists.txt b/deployments/attestation/opteesp/CMakeLists.txt
deleted file mode 100644
index 49bba4c2d..000000000
--- a/deployments/attestation/opteesp/CMakeLists.txt
+++ /dev/null
@@ -1,163 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
-
-# Set default platform.
-set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
-include(../../deployment.cmake REQUIRED)
-
-#-------------------------------------------------------------------------------
-# The CMakeLists.txt for building the attestation deployment for opteesp
-#
-# Builds the attestation service provider for running in an SEL0 secure partition
-# hosted by OPTEE in the role of SPM.
-#-------------------------------------------------------------------------------
-include(${TS_ROOT}/environments/opteesp/env.cmake)
-project(trusted-services LANGUAGES C ASM)
-add_executable(attestation)
-target_include_directories(attestation PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
-set(SP_UUID "a1baf155-8876-4695-8f7c-54955e8db974")
-set(TRACE_PREFIX "ATT" CACHE STRING "Trace prefix")
-
-
-# Include SP DEV KIT interface
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit REQUIRED)
-sp_dev_kit_configure_linking(TARGET attestation DEFINES ARM64=1)
-target_link_libraries(attestation PRIVATE ${SP_DEV_KIT_LIBRARIES})
-
-#-------------------------------------------------------------------------------
-# Default deployment specific configuration
-#
-#-------------------------------------------------------------------------------
-set(TS_NO_FLOAT_HW ON)
-
-#-------------------------------------------------------------------------------
-# Components that are specific to deployment in the opteesp environment.
-#
-#-------------------------------------------------------------------------------
-add_components(TARGET "attestation"
- BASE_DIR ${TS_ROOT}
- COMPONENTS
- "components/common/tlv"
- "components/common/trace"
- "components/common/utils"
- "components/common/endian"
- "components/common/uuid"
- "components/config/ramstore"
- "components/config/loader/sp"
- "components/messaging/ffa/libsp"
- "components/rpc/ffarpc/endpoint"
- "components/rpc/ffarpc/caller/sp"
- "components/rpc/common/caller"
- "components/rpc/common/interface"
- "components/service/common/include"
- "components/service/common/client"
- "components/service/common/provider"
- "components/service/locator"
- "components/service/locator/interface"
- "components/service/locator/sp"
- "components/service/locator/sp/ffa"
- "components/service/attestation/include"
- "components/service/attestation/claims"
- "components/service/attestation/claims/sources/boot_seed_generator"
- "components/service/attestation/claims/sources/null_lifecycle"
- "components/service/attestation/claims/sources/instance_id"
- "components/service/attestation/claims/sources/implementation_id"
- "components/service/attestation/claims/sources/event_log"
- "components/service/attestation/claims/sources/event_log/mock"
- "components/service/attestation/reporter/local"
- "components/service/attestation/reporter/eat"
- "components/service/attestation/key_mngr/local"
- "components/service/attestation/provider"
- "components/service/attestation/provider/serializer/packed-c"
- "components/service/crypto/include"
- "components/service/crypto/client/psa"
- "protocols/rpc/common/packed-c"
- "environments/opteesp"
-)
-
-target_sources(attestation PRIVATE
- attestation_sp.c
-)
-
-#-------------------------------------------------------------------------------
-# Set target platform to provide drivers needed by the deployment
-#
-#-------------------------------------------------------------------------------
-add_platform(TARGET "attestation")
-
-#-------------------------------------------------------------------------------
-# Components used from external projects
-#
-#-------------------------------------------------------------------------------
-
-# Qcbor
-set (QCBOR_EXTERNAL_INCLUDE_PATHS ${SP_DEV_KIT_INCLUDE_DIR})
-include(${TS_ROOT}/external/qcbor/qcbor.cmake)
-target_link_libraries(attestation PRIVATE qcbor)
-
-# t_cose
-set (TCOSE_EXTERNAL_INCLUDE_PATHS ${SP_DEV_KIT_INCLUDE_DIR})
-include(${TS_ROOT}/external/t_cose/t_cose.cmake)
-target_link_libraries(attestation PRIVATE t_cose)
-
-#################################################################
-
-target_compile_definitions(attestation PRIVATE
- ARM64=1
-)
-
-target_include_directories(attestation PRIVATE
- ${TS_ROOT}
- ${TS_ROOT}/components
- ${TS_ROOT}/deployments/attestation/opteesp
-)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_compile_options(attestation PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
- -std=c99
- )
-
- # Options for GCC that control linking
- target_link_options(attestation PRIVATE
- -zmax-page-size=4096
- )
- # Options directly for LD, these are not understood by GCC
- target_link_options(attestation PRIVATE
- -Wl,--as-needed
- -Wl,--sort-section=alignment
- # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
- )
-endif()
-
-compiler_generate_stripped_elf(TARGET attestation NAME "${SP_UUID}.stripped.elf" RES STRIPPED_ELF)
-
-######################################## install
-if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
-endif()
-#TODO: api headers
-
-install(TARGETS attestation
- PUBLIC_HEADER DESTINATION ${TS_ENV}/include
- RUNTIME DESTINATION ${TS_ENV}/bin
- )
-install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
-
-get_property(_PROTO_FILES TARGET attestation PROPERTY PROTOBUF_FILES)
-install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
-
-
-set(EXPORT_SP_NAME "attestation")
-set(EXPORT_SP_UUID ${SP_UUID})
-include(${TS_ROOT}/environments/opteesp/ExportSp.cmake)
diff --git a/deployments/attestation/opteesp/attestation_sp.c b/deployments/attestation/opteesp/attestation_sp.c
deleted file mode 100644
index 6e05a041c..000000000
--- a/deployments/attestation/opteesp/attestation_sp.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <rpc/ffarpc/endpoint/ffarpc_call_ep.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <config/ramstore/config_ramstore.h>
-#include <config/loader/sp/sp_config_loader.h>
-#include <service/attestation/provider/attest_provider.h>
-#include <service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h>
-#include <service/attestation/claims/claims_register.h>
-#include <service/attestation/claims/sources/event_log/event_log_claim_source.h>
-#include <service/attestation/claims/sources/boot_seed_generator/boot_seed_generator.h>
-#include <service/attestation/claims/sources/null_lifecycle/null_lifecycle_claim_source.h>
-#include <service/attestation/claims/sources/instance_id/instance_id_claim_source.h>
-#include <service/attestation/claims/sources/implementation_id/implementation_id_claim_source.h>
-#include <service/attestation/key_mngr/local/local_attest_key_mngr.h>
-#include <service/crypto/client/psa/psa_crypto_client.h>
-#include <service_locator.h>
-#include <psa/crypto.h>
-#include <ffa_api.h>
-#include <sp_api.h>
-#include <sp_rxtx.h>
-#include <trace.h>
-
-uint16_t own_id = 0; /* !!Needs refactoring as parameter to ffarpc_caller_init */
-
-
-static int sp_init(uint16_t *own_sp_id);
-static void locate_crypto_service(void);
-
-void __noreturn sp_main(struct ffa_init_info *init_info)
-{
- /* Service provider objects */
- struct attest_provider attest_provider;
- struct rpc_interface *attest_iface;
- struct ffa_call_ep ffarpc_call_ep;
- struct sp_msg req_msg;
-
- /* Claim source objects */
- struct claim_source *claim_source;
- struct event_log_claim_source event_log_claim_source;
- struct boot_seed_generator boot_seed_claim_source;
- struct null_lifecycle_claim_source lifecycle_claim_source;
- struct instance_id_claim_source instance_id_claim_source;
- struct implementation_id_claim_source implementation_id_claim_source;
-
- /*********************************************************
- * Boot phase
- *********************************************************/
- if (sp_init(&own_id) != 0) goto fatal_error;
-
- config_ramstore_init();
- sp_config_load(init_info);
-
- /**
- * Locate crypto service endpoint and establish RPC session
- */
- locate_crypto_service();
-
- /**
- * Register claim sources for deployment
- */
- claims_register_init();
-
- /* Boot measurement claim source */
- claim_source = event_log_claim_source_init_from_config(&event_log_claim_source);
- claims_register_add_claim_source(CLAIM_CATEGORY_BOOT_MEASUREMENT, claim_source);
-
- /* Boot seed claim source */
- claim_source = boot_seed_generator_init(&boot_seed_claim_source);
- claims_register_add_claim_source(CLAIM_CATEGORY_DEVICE, claim_source);
-
- /* Lifecycle state claim source */
- claim_source = null_lifecycle_claim_source_init(&lifecycle_claim_source);
- claims_register_add_claim_source(CLAIM_CATEGORY_DEVICE, claim_source);
-
- /* Instance ID claim source */
- claim_source = instance_id_claim_source_init(&instance_id_claim_source);
- claims_register_add_claim_source(CLAIM_CATEGORY_DEVICE, claim_source);
-
- /* Implementation ID claim source */
- claim_source = implementation_id_claim_source_init(&implementation_id_claim_source,
- "trustedfirmware.org.ts.attestation_sp");
- claims_register_add_claim_source(CLAIM_CATEGORY_DEVICE, claim_source);
-
- /**
- * Initialize the service provider
- */
- local_attest_key_mngr_init(LOCAL_ATTEST_KEY_MNGR_VOLATILE_IAK);
- attest_iface = attest_provider_init(&attest_provider);
-
- attest_provider_register_serializer(&attest_provider,
- TS_RPC_ENCODING_PACKED_C, packedc_attest_provider_serializer_instance());
-
- ffa_call_ep_init(&ffarpc_call_ep, attest_iface);
-
- /*********************************************************
- * End of boot phase
- *********************************************************/
- sp_msg_wait(&req_msg);
-
- while (1) {
-
- struct sp_msg resp_msg;
-
- ffa_call_ep_receive(&ffarpc_call_ep, &req_msg, &resp_msg);
-
- resp_msg.source_id = req_msg.destination_id;
- resp_msg.destination_id = req_msg.source_id;
-
- sp_msg_send_direct_resp(&resp_msg, &req_msg);
- }
-
-fatal_error:
- /* SP is not viable */
- EMSG("Attestation SP error");
- while (1) {}
-}
-
-void sp_interrupt_handler(uint32_t interrupt_id)
-{
- (void)interrupt_id;
-}
-
-static int sp_init(uint16_t *own_sp_id)
-{
- int status = -1;
- ffa_result ffa_res;
- sp_result sp_res;
- static uint8_t tx_buffer[4096] __aligned(4096);
- static uint8_t rx_buffer[4096] __aligned(4096);
-
- sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
- if (sp_res == SP_RESULT_OK) {
- ffa_res = ffa_id_get(own_sp_id);
- if (ffa_res == FFA_OK) {
- status = 0;
- }
- }
-
- return status;
-}
-
-void locate_crypto_service(void)
-{
- service_locator_init();
-
- int status;
-
- /* todo - add option to use configurable crypto service location */
- struct service_context *crypto_service_context =
- service_locator_query("sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0:0", &status);
-
- if (crypto_service_context) {
-
- struct rpc_caller *caller;
-
- if (service_context_open(crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller)) {
-
- psa_crypto_client_init(caller);
- }
- }
-
- psa_crypto_init();
-}
diff --git a/deployments/attestation/opteesp/attestation_sp.h b/deployments/attestation/opteesp/attestation_sp.h
deleted file mode 100644
index 7c4af581b..000000000
--- a/deployments/attestation/opteesp/attestation_sp.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef ATTESTATION_SP_H
-#define ATTESTATION_SP_H
-
-#define ATTESTATION_SP_UUID \
- {0xa1baf155, 0x8876, 0x4695, \
- {0x8f, 0x7c, 0x54, 0x95, 0x5e, 0x8d, 0xb9, 0x74}}
-
-#define ATTESTATION_SP_UUID_BYTES \
- {0xa1, 0xba, 0xf1, 0x55, 0x88, 0x76, 0x46, 0x95, \
- 0x8f, 0x7c, 0x54, 0x95, 0x5e, 0x8d, 0xb9, 0x74}
-
-#endif /* ATTESTATION_SP_H */
diff --git a/deployments/attestation/opteesp/optee_sp_user_defines.h b/deployments/attestation/opteesp/optee_sp_user_defines.h
deleted file mode 100644
index 23c67b66a..000000000
--- a/deployments/attestation/opteesp/optee_sp_user_defines.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_HEADER_DEFINES_H
-#define SP_HEADER_DEFINES_H
-
-/* To get UUID definition */
-#include "attestation_sp.h"
-
-#define OPTEE_SP_UUID ATTESTATION_SP_UUID
-#define OPTEE_SP_FLAGS 0
-
-/* Provisioned stack size */
-#define OPTEE_SP_STACK_SIZE (64 * 1024)
-
-/* Provisioned heap size */
-#define OPTEE_SP_HEAP_SIZE (32 * 1024)
-
-#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/block-storage/block-storage.cmake b/deployments/block-storage/block-storage.cmake
new file mode 100644
index 000000000..22760f518
--- /dev/null
+++ b/deployments/block-storage/block-storage.cmake
@@ -0,0 +1,28 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Common components used for any deployment of the block-storage service
+# provider.
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/tlv"
+ "components/common/uuid"
+ "components/common/endian"
+ "components/service/common/include"
+ "components/service/common/provider"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/provider"
+ "components/service/block_storage/provider/serializer/packed-c"
+)
+
+#################################################################
+
+target_include_directories(block-storage PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
diff --git a/deployments/block-storage/config/cfi-flash-optee/CMakeLists.txt b/deployments/block-storage/config/cfi-flash-optee/CMakeLists.txt
new file mode 100644
index 000000000..b6501f25d
--- /dev/null
+++ b/deployments/block-storage/config/cfi-flash-optee/CMakeLists.txt
@@ -0,0 +1,102 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+#-------------------------------------------------------------------------------
+# Set default platform. TS_PLATFORM should be set externally to build for
+# an alternative platform from the default one.
+#
+#-------------------------------------------------------------------------------
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the block_storage deployment for opteesp
+#
+# Builds the block_storage service provider for running in an SEL0 secure partition
+# hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(block-storage)
+target_include_directories(block-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "63646e80-eb52-462f-ac4f-8cdf3987519c")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "120 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "BLOCK" CACHE STRING "Trace prefix")
+
+target_include_directories(block-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Deployment specific components. This deployment uses an infrastructure that
+# that provides ram-backed block stoarged, configured with storage partitions
+# that conform to the 'ref' scheme used for test.
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/block_storage_sp.cmake REQUIRED)
+include(../../block-storage.cmake REQUIRED)
+
+# Replace with suitable infrastructure when suitable nor flash adapter is implemented
+include(../../infra/ref-ram.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# External project dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET "block-storage")
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "block-storage")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(block-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(block-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+
+install(TARGETS block-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "block-storage"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_block-storage.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/block-storage/config/cfi-flash-optee/default_block-storage.dts.in b/deployments/block-storage/config/cfi-flash-optee/default_block-storage.dts.in
new file mode 100644
index 000000000..0a97cb53e
--- /dev/null
+++ b/deployments/block-storage/config/cfi-flash-optee/default_block-storage.dts.in
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "BlockStorage";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/block-storage/config/cfi-flash-optee/optee_sp_user_defines.h b/deployments/block-storage/config/cfi-flash-optee/optee_sp_user_defines.h
new file mode 100644
index 000000000..798e8736f
--- /dev/null
+++ b/deployments/block-storage/config/cfi-flash-optee/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/block-storage/config/default-opteesp/CMakeLists.txt b/deployments/block-storage/config/default-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..5592dcd0a
--- /dev/null
+++ b/deployments/block-storage/config/default-opteesp/CMakeLists.txt
@@ -0,0 +1,80 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the block_storage deployment for opteesp
+#
+# Builds the block_storage service provider for running in an SEL0 secure partition
+# hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(block-storage)
+target_include_directories(block-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "63646e80-eb52-462f-ac4f-8cdf3987519c")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "120 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "BLOCK" CACHE STRING "Trace prefix")
+
+target_include_directories(block-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Deployment specific components. This deployment uses an infrastructure that
+# that provides ram-backed block stoarged, configured with storage partitions
+# that conform to the 'ref' scheme used for test.
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/block_storage_sp.cmake REQUIRED)
+include(../../block-storage.cmake REQUIRED)
+include(../../infra/ref-ram.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(block-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(block-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+
+install(TARGETS block-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "block-storage"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_block-storage.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/block-storage/config/default-opteesp/default_block-storage.dts.in b/deployments/block-storage/config/default-opteesp/default_block-storage.dts.in
new file mode 100644
index 000000000..0a97cb53e
--- /dev/null
+++ b/deployments/block-storage/config/default-opteesp/default_block-storage.dts.in
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "BlockStorage";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/block-storage/config/default-opteesp/optee_sp_user_defines.h b/deployments/block-storage/config/default-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..798e8736f
--- /dev/null
+++ b/deployments/block-storage/config/default-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/block-storage/config/default-sp/CMakeLists.txt b/deployments/block-storage/config/default-sp/CMakeLists.txt
new file mode 100644
index 000000000..2241c9c46
--- /dev/null
+++ b/deployments/block-storage/config/default-sp/CMakeLists.txt
@@ -0,0 +1,85 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the block-storage deployment for generic sp
+# environment.
+#
+# Builds the block storage service provider for running in an SEL0 secure partition
+# hosted by any SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(block-storage)
+target_include_directories(block-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+set(SP_NAME "block-storage")
+set(SP_BIN_UUID_CANON "63646e80-eb52-462f-ac4f-8cdf3987519c")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "120 * 1024" CACHE STRING "SP heap size in bytes")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+set(TRACE_PREFIX "BLOCK" CACHE STRING "Trace prefix")
+
+#-------------------------------------------------------------------------------
+# Deployment specific components. This deployment uses an infrastructure that
+# that provides ram-backed block stoarged, configured with storage partitions
+# that conform to the 'ref' scheme used for test.
+#-------------------------------------------------------------------------------
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+include(../../env/commonsp/block_storage_sp.cmake REQUIRED)
+include(../../block-storage.cmake REQUIRED)
+include(../../infra/ref-ram.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(block-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(block-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET block-storage NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET block-storage NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS block-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake REQUIRED)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/block-storage/config/default-sp/default_block-storage.dts.in b/deployments/block-storage/config/default-sp/default_block-storage.dts.in
new file mode 100644
index 000000000..5d1cf5d08
--- /dev/null
+++ b/deployments/block-storage/config/default-sp/default_block-storage.dts.in
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "BlockStorage";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ #include "@EXPORT_DTS_MEM_REGIONS@"
+ };
+};
diff --git a/deployments/block-storage/config/edk2-secure-flash-opteesp/CMakeLists.txt b/deployments/block-storage/config/edk2-secure-flash-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..5b8bedf69
--- /dev/null
+++ b/deployments/block-storage/config/edk2-secure-flash-opteesp/CMakeLists.txt
@@ -0,0 +1,103 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+#-------------------------------------------------------------------------------
+# Set default platform. TS_PLATFORM should be set externally to build for
+# an alternative platform from the default one.
+#
+#-------------------------------------------------------------------------------
+set(TS_PLATFORM "arm/n1sdp" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the block_storage service for opteesp on a
+# platform with a dedicated secure flash device with driver support from the
+# EDK2 project. Platform drivers that the deployment depends on are fetched
+# from the edk2-platforms upstream repo and built into the SP image genereated
+# by the build process.
+#
+# NOTE: In its current state, this configuration doesn't yet build successfully
+# as problems such as resolving EDK2 header file dependencies still need to
+# be resolved.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(block-storage)
+target_include_directories(block-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "63646e80-eb52-462f-ac4f-8cdf3987519c")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "120 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "BLOCK" CACHE STRING "Trace prefix")
+
+target_include_directories(block-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Deployment specific components.
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/block_storage_sp.cmake REQUIRED)
+include(../../block-storage.cmake REQUIRED)
+
+# Replace with suitable infrastructure when edk2 driver building in TS is supported
+include(../../infra/ref-ram.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# External project dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/edk2_platforms/morello.cmake)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "block-storage")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(block-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(block-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+
+install(TARGETS block-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "block-storage"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_block-storage.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/block-storage/config/edk2-secure-flash-opteesp/default_block-storage.dts.in b/deployments/block-storage/config/edk2-secure-flash-opteesp/default_block-storage.dts.in
new file mode 100644
index 000000000..0a97cb53e
--- /dev/null
+++ b/deployments/block-storage/config/edk2-secure-flash-opteesp/default_block-storage.dts.in
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "BlockStorage";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/block-storage/config/edk2-secure-flash-opteesp/optee_sp_user_defines.h b/deployments/block-storage/config/edk2-secure-flash-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..798e8736f
--- /dev/null
+++ b/deployments/block-storage/config/edk2-secure-flash-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/block-storage/config/semihosted-opteesp/CMakeLists.txt b/deployments/block-storage/config/semihosted-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..2be517640
--- /dev/null
+++ b/deployments/block-storage/config/semihosted-opteesp/CMakeLists.txt
@@ -0,0 +1,99 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+#-------------------------------------------------------------------------------
+# Set default platform.
+#
+#-------------------------------------------------------------------------------
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the block_storage deployment for opteesp
+#
+# Builds the block_storage service provider for running in an SEL0 secure partition
+# hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(block-storage)
+target_include_directories(block-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "63646e80-eb52-462f-ac4f-8cdf3987519c")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "120 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "BLOCK" CACHE STRING "Trace prefix")
+
+target_include_directories(block-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# External project source-level dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET "block-storage")
+
+#-------------------------------------------------------------------------------
+# Deployment specific components. This deployment uses an infrastructure that
+# that provides NV storage backed by a semihosted file residing in a host
+# device filesystem.
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/block_storage_sp.cmake REQUIRED)
+include(../../block-storage.cmake REQUIRED)
+include(../../infra/semihosted.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "block-storage")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(block-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(block-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+
+install(TARGETS block-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "block-storage"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_block-storage.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/block-storage/config/semihosted-opteesp/default_block-storage.dts.in b/deployments/block-storage/config/semihosted-opteesp/default_block-storage.dts.in
new file mode 100644
index 000000000..0a97cb53e
--- /dev/null
+++ b/deployments/block-storage/config/semihosted-opteesp/default_block-storage.dts.in
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "BlockStorage";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/block-storage/config/semihosted-opteesp/optee_sp_user_defines.h b/deployments/block-storage/config/semihosted-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..798e8736f
--- /dev/null
+++ b/deployments/block-storage/config/semihosted-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/block-storage/env/commonsp/block_storage_sp.c b/deployments/block-storage/env/commonsp/block_storage_sp.c
new file mode 100644
index 000000000..10ede2d13
--- /dev/null
+++ b/deployments/block-storage/env/commonsp/block_storage_sp.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "common/crc32/crc32.h"
+#include "rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "config/ramstore/config_ramstore.h"
+#include "config/loader/sp/sp_config_loader.h"
+#include "service/block_storage/provider/block_storage_provider.h"
+#include "service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h"
+#include "service/block_storage/factory/block_store_factory.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_messaging.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+
+
+static bool sp_init(uint16_t *own_sp_id);
+
+void __noreturn sp_main(union ffa_boot_info *boot_info)
+{
+ struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
+ struct block_storage_provider service_provider = { 0 };
+ struct block_store *backend = NULL;
+ struct rpc_service_interface *service_iface = NULL;
+ struct sp_msg req_msg = { 0 };
+ struct sp_msg resp_msg = { 0 };
+ uint16_t own_id = 0;
+ sp_result result = SP_RESULT_INTERNAL_ERROR;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Boot phase */
+ if (!sp_init(&own_id)) {
+ EMSG("Failed to init SP");
+ goto fatal_error;
+ }
+
+ config_ramstore_init();
+
+ if (!sp_config_load(boot_info)) {
+ EMSG("Failed to load SP config");
+ goto fatal_error;
+ }
+
+ crc32_init();
+
+ /* Initialise the service provider and backend block store */
+ backend = block_store_factory_create();
+ if (!backend) {
+ EMSG("Failed to create block store");
+ goto fatal_error;
+ }
+
+ service_iface = block_storage_provider_init(
+ &service_provider,
+ backend);
+ if (!service_iface) {
+ EMSG("Failed to init service provider");
+ goto fatal_error;
+ }
+
+ block_storage_provider_register_serializer(&service_provider,
+ packedc_block_storage_serializer_instance());
+
+ /* Associate service interface with FFA call endpoint */
+ rpc_status = ts_rpc_endpoint_sp_init(&rpc_endpoint, 1, 16);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to initialize RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, service_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /* End of boot phase */
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ ts_rpc_endpoint_sp_receive(&rpc_endpoint, &req_msg, &resp_msg);
+
+ result = sp_msg_send_direct_resp(&resp_msg, &req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("Block storage SP error");
+ while (1) {}
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
+
+static bool sp_init(uint16_t *own_id)
+{
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ static uint8_t tx_buffer[4096] __aligned(4096);
+ static uint8_t rx_buffer[4096] __aligned(4096);
+
+ sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", sp_res);
+ return false;
+ }
+
+ sp_res = sp_discovery_own_id_get(own_id);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", sp_res);
+ return false;
+ }
+
+ return true;
+}
diff --git a/deployments/block-storage/env/commonsp/block_storage_sp.cmake b/deployments/block-storage/env/commonsp/block_storage_sp.cmake
new file mode 100644
index 000000000..78da5d757
--- /dev/null
+++ b/deployments/block-storage/env/commonsp/block_storage_sp.cmake
@@ -0,0 +1,32 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the block-storage service provider
+# within a secure partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for block-storage sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/crc32"
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/common/interface"
+ "components/rpc/common/endpoint"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/endpoint/sp"
+)
+
+target_sources(block-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/block_storage_sp.c
+)
diff --git a/deployments/block-storage/env/commonsp/block_storage_sp.h b/deployments/block-storage/env/commonsp/block_storage_sp.h
new file mode 100644
index 000000000..97ec07d80
--- /dev/null
+++ b/deployments/block-storage/env/commonsp/block_storage_sp.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BLOCK_STORAGE_SP_H
+#define BLOCK_STORAGE_SP_H
+
+#endif /* BLOCK_STORAGE_SP_H */
diff --git a/deployments/block-storage/infra/ref-ram.cmake b/deployments/block-storage/infra/ref-ram.cmake
new file mode 100644
index 000000000..2e1ca559b
--- /dev/null
+++ b/deployments/block-storage/infra/ref-ram.cmake
@@ -0,0 +1,24 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Lists components that provide an infrastructure layer for the block-storage
+# service provider that uses a ram-backed block store, partitioned by default
+# using the 'ref' configuration. This infrastructure is intended for test
+# purposes.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/ram"
+ "components/service/block_storage/block_store/partitioned"
+ "components/service/block_storage/config/ref"
+ "components/service/block_storage/factory/ref_ram"
+)
diff --git a/deployments/block-storage/infra/semihosted.cmake b/deployments/block-storage/infra/semihosted.cmake
new file mode 100644
index 000000000..e9637ad7f
--- /dev/null
+++ b/deployments/block-storage/infra/semihosted.cmake
@@ -0,0 +1,34 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# A block-storage infrastructure for use on virtual platforms where storage
+# is provided by file residing in the host's filesystem. If the file contains
+# a GPT, it will be used to configure storage partitions.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "block-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/semihosting"
+ "components/service/block_storage/block_store/partitioned"
+ "components/service/block_storage/factory/semihosting"
+ "components/service/block_storage/config/gpt"
+ "components/media/disk"
+ "components/media/volume"
+ "components/media/volume/index"
+ "components/media/volume/base_io_dev"
+ "components/media/volume/block_volume"
+)
+
+#-------------------------------------------------------------------------------
+# This infrastructure depends on platform specific drivers
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "block-storage")
diff --git a/deployments/component-test/arm-linux/CMakeLists.txt b/deployments/component-test/arm-linux/CMakeLists.txt
index b145719be..f104dd659 100644
--- a/deployments/component-test/arm-linux/CMakeLists.txt
+++ b/deployments/component-test/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
@@ -26,7 +26,7 @@ add_components(
)
include(${TS_ROOT}/external/CppUTest/CppUTest.cmake)
-target_link_libraries(component-test PRIVATE CppUTest)
+target_link_libraries(component-test PRIVATE ${CppUTest_LIBRARIES})
#-------------------------------------------------------------------------------
# Components that are specific to deployment in the arm-linux environment.
@@ -50,5 +50,4 @@ include(../component-test.cmake REQUIRED)
# Define library options and dependencies.
#
#-------------------------------------------------------------------------------
-env_set_link_options(TGT component-test)
target_link_libraries(component-test PRIVATE stdc++ gcc m)
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index a0233c345..b55706fa1 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -10,6 +10,18 @@
# different environments. Used for running standalone component tests
# contained within a single executable.
#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# External project source-level dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET "component-test")
+
+#-------------------------------------------------------------------------------
+# Common components from TS project
+#
+#-------------------------------------------------------------------------------
add_components(
TARGET "component-test"
BASE_DIR ${TS_ROOT}
@@ -21,13 +33,18 @@ add_components(
"components/common/uuid/test"
"components/common/tlv"
"components/common/tlv/test"
+ "components/common/trace"
"components/common/endian"
"components/common/endian/test"
+ "components/common/crc32"
+ "components/common/crc32/test"
"components/config/ramstore"
"components/config/ramstore/test"
+ "components/messaging/ffa/libsp/mock"
"components/rpc/common/caller"
+ "components/rpc/common/endpoint"
"components/rpc/common/interface"
- "components/rpc/common/demux"
+ "components/rpc/common/test"
"components/rpc/common/test/protocol"
"components/rpc/direct"
"components/rpc/dummy"
@@ -45,11 +62,10 @@ add_components(
"components/service/locator/standalone/services/protected-storage"
"components/service/locator/standalone/services/test-runner"
"components/service/locator/standalone/services/attestation"
+ "components/service/locator/standalone/services/block-storage"
+ "components/service/locator/standalone/services/fwu"
+ "components/service/locator/standalone/services/rpmb"
"components/service/locator/standalone/services/smm-variable"
- "components/service/discovery/client"
- "components/service/discovery/provider"
- "components/service/discovery/provider/serializer/packed-c"
- "components/service/discovery/test/service"
"components/service/attestation/include"
"components/service/attestation/claims"
"components/service/attestation/claims/sources/boot_seed_generator"
@@ -69,6 +85,49 @@ add_components(
"components/service/attestation/client/provision"
"components/service/attestation/test/component"
"components/service/attestation/test/service"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/ram"
+ "components/service/block_storage/block_store/device/ram/test"
+ "components/service/block_storage/block_store/device/null"
+ "components/service/block_storage/block_store/device/file"
+ "components/service/block_storage/block_store/device/file/test"
+ "components/service/block_storage/block_store/device/rpmb"
+ "components/service/block_storage/block_store/client"
+ "components/service/block_storage/block_store/partitioned"
+ "components/service/block_storage/block_store/partitioned/test"
+ "components/service/block_storage/provider"
+ "components/service/block_storage/provider/serializer/packed-c"
+ "components/service/block_storage/config/ref"
+ "components/service/block_storage/config/gpt"
+ "components/service/block_storage/factory/ref_ram"
+ "components/service/block_storage/factory/ref_ram_gpt"
+ "components/service/block_storage/factory/client"
+ "components/service/block_storage/factory/rpmb"
+ "components/service/fwu/agent"
+ "components/service/fwu/fw_store/banked"
+ "components/service/fwu/fw_store/banked/metadata_serializer/v1"
+ "components/service/fwu/fw_store/banked/metadata_serializer/v2"
+ "components/service/fwu/fw_store/banked/test"
+ "components/service/fwu/installer"
+ "components/service/fwu/installer/raw"
+ "components/service/fwu/installer/raw/test"
+ "components/service/fwu/installer/copy"
+ "components/service/fwu/installer/copy/test"
+ "components/service/fwu/installer/factory/default"
+ "components/service/fwu/installer/factory/default/test"
+ "components/service/fwu/inspector/mock"
+ "components/service/fwu/inspector/direct"
+ "components/service/fwu/provider"
+ "components/service/fwu/provider/serializer/packed-c"
+ "components/service/fwu/test/fwu_client/direct"
+ "components/service/fwu/test/fwu_dut"
+ "components/service/fwu/test/fwu_dut/sim"
+ "components/service/fwu/test/fwu_dut_factory/sim"
+ "components/service/fwu/test/metadata_checker"
+ "components/service/fwu/test/metadata_fetcher/volume"
+ "components/service/fwu/test/image_directory_checker"
+ "components/service/fwu/test/ref_scenarios"
"components/service/crypto/client/cpp"
"components/service/crypto/client/cpp/protocol/protobuf"
"components/service/crypto/client/cpp/protocol/packed-c"
@@ -85,8 +144,11 @@ add_components(
"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
"components/service/crypto/provider/extension/mac"
"components/service/crypto/provider/extension/mac/serializer/packed-c"
+ "components/service/crypto/provider/extension/aead"
+ "components/service/crypto/provider/extension/aead/serializer/packed-c"
"components/service/crypto/provider/test"
"components/service/crypto/backend/mbedcrypto"
+ "components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509"
"components/service/crypto/factory/full"
"components/service/crypto/test/unit"
"components/service/crypto/test/service"
@@ -101,6 +163,17 @@ add_components(
"components/service/crypto/test/service/extension/key_derivation"
"components/service/crypto/test/service/extension/key_derivation/packed-c"
"components/service/crypto/test/protocol"
+ "components/service/rpmb/backend"
+ "components/service/rpmb/backend/emulated"
+ "components/service/rpmb/backend/mock"
+ "components/service/rpmb/backend/mock/test"
+ "components/service/rpmb/client"
+ "components/service/rpmb/frontend"
+ "components/service/rpmb/frontend/platform/default"
+ "components/service/rpmb/frontend/platform/mock"
+ "components/service/rpmb/frontend/platform/mock/test"
+ "components/service/rpmb/frontend/test"
+ "components/service/rpmb/provider"
"components/service/secure_storage/include"
"components/service/secure_storage/frontend/psa/its"
"components/service/secure_storage/frontend/psa/its/test"
@@ -116,12 +189,24 @@ add_components(
"components/service/secure_storage/backend/secure_flash_store/test"
"components/service/secure_storage/backend/secure_flash_store/flash_fs"
"components/service/secure_storage/backend/secure_flash_store/flash"
+ "components/service/secure_storage/backend/secure_flash_store/flash/ram"
+ "components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter"
"components/service/test_runner/provider"
"components/service/test_runner/provider/serializer/packed-c"
"components/service/test_runner/provider/backend/null"
- "components/service/smm_variable/provider"
- "components/service/smm_variable/backend"
- "components/service/smm_variable/backend/test"
+ "components/service/uefi/smm_variable/provider"
+ "components/service/uefi/smm_variable/backend"
+ "components/service/uefi/smm_variable/backend/test"
+ "components/media/disk"
+ "components/media/disk/disk_images"
+ "components/media/disk/formatter"
+ "components/media/disk/gpt_iterator"
+ "components/media/disk/test"
+ "components/media/volume"
+ "components/media/volume/index"
+ "components/media/volume/base_io_dev"
+ "components/media/volume/block_volume"
+ "components/media/volume/block_volume/test"
"protocols/rpc/common/protobuf"
"protocols/rpc/common/packed-c"
"protocols/service/crypto/packed-c"
@@ -130,6 +215,15 @@ add_components(
)
#-------------------------------------------------------------------------------
+# Component configurations
+#
+#-------------------------------------------------------------------------------
+target_compile_definitions(component-test PRIVATE
+ "TRACE_PREFIX=\"TEST\""
+ "TRACE_LEVEL=0"
+)
+
+#-------------------------------------------------------------------------------
# Components used from external projects
#
#-------------------------------------------------------------------------------
@@ -139,9 +233,17 @@ include(${TS_ROOT}/external/nanopb/nanopb.cmake)
target_link_libraries(component-test PRIVATE nanopb::protobuf-nanopb-static)
protobuf_generate_all(TGT "component-test" NAMESPACE "protobuf" BASE_DIR "${TS_ROOT}/protocols")
-# Mbed TLS provides libmbedcrypto
+# MbedTLS
+set(MBEDTLS_USER_CONFIG_FILE "${TS_ROOT}/external/MbedTLS/config/libmbedx509.h"
+ CACHE STRING "Configuration file for Mbed TLS" FORCE)
include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(component-test PRIVATE mbedcrypto)
+target_link_libraries(component-test PRIVATE MbedTLS::mbedcrypto)
+target_link_libraries(component-test PRIVATE MbedTLS::mbedx509)
+
+# Pass the location of the mbedtls config file to C preprocessor.
+target_compile_definitions(component-test PRIVATE
+ MBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}"
+)
# Qcbor
include(${TS_ROOT}/external/qcbor/qcbor.cmake)
@@ -158,4 +260,6 @@ target_link_libraries(component-test PRIVATE t_cose)
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
endif()
-install(TARGETS component-test DESTINATION ${TS_ENV}/bin)
+install(TARGETS component-test
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include)
diff --git a/deployments/component-test/linux-pc/CMakeLists.txt b/deployments/component-test/linux-pc/CMakeLists.txt
index c2514a8e1..6cf24b981 100644
--- a/deployments/component-test/linux-pc/CMakeLists.txt
+++ b/deployments/component-test/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
diff --git a/deployments/crypto/config/default-opteesp/CMakeLists.txt b/deployments/crypto/config/default-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..1e4069d66
--- /dev/null
+++ b/deployments/crypto/config/default-opteesp/CMakeLists.txt
@@ -0,0 +1,98 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+
+# Te crypto SP is big. Set default build type to MinSizWithDebInfo to avoid running ouf of
+# secure memory on low resource IoT platforms.
+if (NOT DEFINED CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "MinSizWithDebInfo" CACHE STRING "Build type.")
+endif()
+
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the crypto deployment for opteesp
+#
+# Builds the Crypto service provider for running in an SEL0 secure partition
+# hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(crypto)
+target_include_directories(crypto PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "490 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "CRYPTO" CACHE STRING "Trace prefix")
+
+target_include_directories(crypto PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Deployment specific components
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "crypto"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/crypto_sp.cmake REQUIRED)
+include(../../crypto.cmake REQUIRED)
+include(../../infra/baremetal-psa.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "crypto")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(crypto PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(crypto PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+#TODO: api headers
+
+install(TARGETS crypto
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+get_property(_PROTO_FILES TARGET crypto PROPERTY PROTOBUF_FILES)
+install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "crypto"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_crypto.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/crypto/opteesp/default_crypto.dts.in b/deployments/crypto/config/default-opteesp/default_crypto.dts.in
index 2646239d9..c9006361d 100644
--- a/deployments/crypto/opteesp/default_crypto.dts.in
+++ b/deployments/crypto/config/default-opteesp/default_crypto.dts.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,7 +15,9 @@
exception-level = <1>; /* S-EL0 */
execution-state = <0>; /* AArch64 */
xlat-granule = <0>; /* 4KiB */
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
device-regions {
compatible = "arm,ffa-manifest-device-regions";
diff --git a/deployments/crypto/config/default-opteesp/optee_sp_user_defines.h b/deployments/crypto/config/default-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..bbcc12be7
--- /dev/null
+++ b/deployments/crypto/config/default-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/crypto/config/default-sp/CMakeLists.txt b/deployments/crypto/config/default-sp/CMakeLists.txt
new file mode 100644
index 000000000..83594c5e2
--- /dev/null
+++ b/deployments/crypto/config/default-sp/CMakeLists.txt
@@ -0,0 +1,98 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+
+# Te crypto SP is big. Set default build type to MinSizWithDebInfo to avoid running ouf of
+# secure memory on low resource IoT platforms.
+if (NOT DEFINED CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "MinSizWithDebInfo" CACHE STRING "Build type.")
+endif()
+
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the crypto deployment for generic sp
+# environment.
+#
+# Builds the Crypto service provider for running in an SEL0 secure partition
+# hosted by any SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(crypto)
+target_include_directories(crypto PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_NAME "crypto")
+set(SP_BIN_UUID_CANON "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(TRACE_PREFIX "CRYPTO" CACHE STRING "Trace prefix")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+set(SP_HEAP_SIZE "490 * 1024" CACHE STRING "Heap size")
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the opteesp environment.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "crypto"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+include(../../env/commonsp/crypto_sp.cmake REQUIRED)
+include(../../crypto.cmake REQUIRED)
+include(../../infra/baremetal-psa.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "crypto")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(crypto PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(crypto PRIVATE
+ -std=c99
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET crypto NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET crypto NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS crypto
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake REQUIRED)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/crypto/config/default-sp/default_crypto.dts.in b/deployments/crypto/config/default-sp/default_crypto.dts.in
new file mode 100644
index 000000000..fcc7ce58e
--- /dev/null
+++ b/deployments/crypto/config/default-sp/default_crypto.dts.in
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "Crypto";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+
+ device-regions {
+ compatible = "arm,ffa-manifest-device-regions";
+
+ trng {
+ /* Armv8 A Foundation Platform values */
+ base-address = <0x00000000 0x7fe60000>;
+ pages-count = <1>;
+ attributes = <0x3>; /* read-write */
+ };
+ };
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ #include "@EXPORT_DTS_MEM_REGIONS@"
+ };
+};
diff --git a/deployments/crypto/crypto.cmake b/deployments/crypto/crypto.cmake
new file mode 100644
index 000000000..155099c2b
--- /dev/null
+++ b/deployments/crypto/crypto.cmake
@@ -0,0 +1,65 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "crypto"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/tlv"
+ "components/rpc/common/interface"
+ "components/rpc/common/endpoint"
+ "components/service/common/include"
+ "components/service/common/serializer/protobuf"
+ "components/service/common/provider"
+ "components/service/crypto/provider"
+ "components/service/crypto/provider/serializer/protobuf"
+ "components/service/crypto/provider/serializer/packed-c"
+ "components/service/crypto/provider/extension/hash"
+ "components/service/crypto/provider/extension/hash/serializer/packed-c"
+ "components/service/crypto/provider/extension/cipher"
+ "components/service/crypto/provider/extension/cipher/serializer/packed-c"
+ "components/service/crypto/provider/extension/key_derivation"
+ "components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
+ "components/service/crypto/provider/extension/mac"
+ "components/service/crypto/provider/extension/mac/serializer/packed-c"
+ "components/service/crypto/provider/extension/aead"
+ "components/service/crypto/provider/extension/aead/serializer/packed-c"
+ "components/service/crypto/factory/full"
+ "components/service/crypto/backend/mbedcrypto"
+ "components/service/crypto/backend/mbedcrypto/mbedtls_fake_x509"
+ "protocols/rpc/common/packed-c"
+ "protocols/service/crypto/protobuf"
+)
+
+#-------------------------------------------------------------------------------
+# Components used from external projects
+#
+#-------------------------------------------------------------------------------
+
+# Nanopb
+include(${TS_ROOT}/external/nanopb/nanopb.cmake)
+target_link_libraries(crypto PRIVATE nanopb::protobuf-nanopb-static)
+protobuf_generate_all(TGT "crypto" NAMESPACE "protobuf" BASE_DIR "${TS_ROOT}/protocols")
+
+# Mbed TLS provides libmbedcrypto
+set(MBEDTLS_USER_CONFIG_FILE "${TS_ROOT}/external/MbedTLS/config/libmbedx509.h"
+ CACHE STRING "Configuration file for Mbed TLS" FORCE)
+include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
+target_link_libraries(crypto PRIVATE MbedTLS::mbedcrypto)
+target_link_libraries(crypto PRIVATE MbedTLS::mbedx509)
+
+# Provide the config path to mbedtls
+target_compile_definitions(crypto
+ PRIVATE
+ MBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}"
+)
+
+#################################################################
+
+target_include_directories(crypto PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
diff --git a/deployments/crypto/env/commonsp/crypto_sp.c b/deployments/crypto/env/commonsp/crypto_sp.c
new file mode 100644
index 000000000..e671954b6
--- /dev/null
+++ b/deployments/crypto/env/commonsp/crypto_sp.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h"
+#include "service/secure_storage/factory/storage_factory.h"
+#include "service/crypto/factory/crypto_provider_factory.h"
+#include "service/crypto/backend/mbedcrypto/mbedcrypto_backend.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "config/ramstore/config_ramstore.h"
+#include "config/loader/sp/sp_config_loader.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_messaging.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+
+static bool sp_init(uint16_t *own_sp_id);
+
+void __noreturn sp_main(union ffa_boot_info *boot_info)
+{
+ struct crypto_provider *crypto_provider = NULL;
+ struct crypto_provider *crypto_protobuf_provider = NULL;
+ struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
+ struct rpc_service_interface *crypto_iface = NULL;
+ struct rpc_service_interface *crypto_iface_protobuf = NULL;
+ struct sp_msg req_msg = { 0 };
+ struct sp_msg resp_msg = { 0 };
+ struct storage_backend *storage_backend = NULL;
+ uint16_t own_id = 0;
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+ sp_result result = SP_RESULT_INTERNAL_ERROR;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Boot phase */
+ if (!sp_init(&own_id)) {
+ EMSG("Failed to init SP");
+ goto fatal_error;
+ }
+
+ config_ramstore_init();
+
+ if (!sp_config_load(boot_info)) {
+ EMSG("Failed to load SP config");
+ goto fatal_error;
+ }
+
+ /* Create a storage backend for persistent key storage - prefer ITS */
+ storage_backend = storage_factory_create(storage_factory_security_class_INTERNAL_TRUSTED);
+ if (!storage_backend) {
+ EMSG("Failed to create storage factory");
+ goto fatal_error;
+ }
+
+ /* Initialize the crypto service */
+ psa_status = mbedcrypto_backend_init(storage_backend, 0);
+ if (psa_status != PSA_SUCCESS) {
+ EMSG("Failed to init Mbed TLS backend: %d", psa_status);
+ goto fatal_error;
+ }
+
+ crypto_provider = crypto_provider_factory_create();
+ if (!crypto_provider) {
+ EMSG("Failed to create crypto provider factory");
+ goto fatal_error;
+ }
+
+ crypto_protobuf_provider = crypto_protobuf_provider_factory_create();
+ if (!crypto_protobuf_provider) {
+ EMSG("Failed to create crypto protobuf provider factory");
+ goto fatal_error;
+ }
+
+ crypto_iface = service_provider_get_rpc_interface(&crypto_provider->base_provider);
+ if (!crypto_iface) {
+ EMSG("Failed to create service provider RPC interface");
+ goto fatal_error;
+ }
+
+ crypto_iface_protobuf = service_provider_get_rpc_interface(
+ &crypto_protobuf_provider->base_provider);
+ if (!crypto_iface_protobuf) {
+ EMSG("Failed to create service provider RPC interface");
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_init(&rpc_endpoint, 2, 16);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to initialize RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, crypto_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, crypto_iface_protobuf);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /* End of boot phase */
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ ts_rpc_endpoint_sp_receive(&rpc_endpoint, &req_msg, &resp_msg);
+
+ result = sp_msg_send_direct_resp(&resp_msg, &req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("Crypto SP error");
+ while (1) {}
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
+
+static bool sp_init(uint16_t *own_id)
+{
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ static uint8_t tx_buffer[4096] __aligned(4096);
+ static uint8_t rx_buffer[4096] __aligned(4096);
+
+ sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", sp_res);
+ return false;
+ }
+
+ sp_res = sp_discovery_own_id_get(own_id);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", sp_res);
+ return false;
+ }
+
+ return true;
+}
diff --git a/deployments/crypto/env/commonsp/crypto_sp.cmake b/deployments/crypto/env/commonsp/crypto_sp.cmake
new file mode 100644
index 000000000..5888b6a83
--- /dev/null
+++ b/deployments/crypto/env/commonsp/crypto_sp.cmake
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the crypto service provider
+# within a secure partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for crypto sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "crypto"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/common/endpoint"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/endpoint/sp"
+)
+
+target_sources(crypto PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/crypto_sp.c
+)
diff --git a/deployments/crypto/env/commonsp/crypto_sp.h b/deployments/crypto/env/commonsp/crypto_sp.h
new file mode 100644
index 000000000..8771f00d7
--- /dev/null
+++ b/deployments/crypto/env/commonsp/crypto_sp.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_SP_H
+#define CRYPTO_SP_H
+
+#endif /* CRYPTO_SP_H */
diff --git a/deployments/crypto/infra/baremetal-psa.cmake b/deployments/crypto/infra/baremetal-psa.cmake
new file mode 100644
index 000000000..2aa1562a2
--- /dev/null
+++ b/deployments/crypto/infra/baremetal-psa.cmake
@@ -0,0 +1,33 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Defines an infrastructure for the crypto service provider that uses a
+# baremetal platform TRNG driver and PSA storage for persistent key storage.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "crypto"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/rpc/ts_rpc/caller/sp"
+ "components/rpc/common/caller"
+ "components/service/common/client"
+ "components/service/crypto/backend/mbedcrypto/trng_adapter/platform"
+ "components/service/secure_storage/include"
+ "components/service/secure_storage/frontend/psa/its"
+ "components/service/secure_storage/backend/secure_storage_client"
+ "components/service/secure_storage/backend/null_store"
+ "components/service/secure_storage/factory/sp/rot_store"
+ "protocols/service/secure_storage/packed-c"
+)
+
+#-------------------------------------------------------------------------------
+# This infrastructure depends on platform specific drivers
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "crypto")
diff --git a/deployments/crypto/opteesp/.gitignore b/deployments/crypto/opteesp/.gitignore
deleted file mode 100644
index 378eac25d..000000000
--- a/deployments/crypto/opteesp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-build
diff --git a/deployments/crypto/opteesp/CMakeLists.txt b/deployments/crypto/opteesp/CMakeLists.txt
deleted file mode 100644
index a9b1b9025..000000000
--- a/deployments/crypto/opteesp/CMakeLists.txt
+++ /dev/null
@@ -1,167 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
-
-# Set default platform.
-set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
-include(../../deployment.cmake REQUIRED)
-
-#-------------------------------------------------------------------------------
-# The CMakeLists.txt for building the crypto deployment for opteesp
-#
-# Builds the Crypto service provider for running in an SEL0 secure partition
-# hosted by OPTEE in the role of SPM.
-#-------------------------------------------------------------------------------
-include(${TS_ROOT}/environments/opteesp/env.cmake)
-project(trusted-services LANGUAGES C ASM)
-add_executable(crypto-sp)
-target_include_directories(crypto-sp PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
-set(SP_UUID "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0")
-set(TRACE_PREFIX "CRYPTO" CACHE STRING "Trace prefix")
-
-
-# Include SP DEV KIT interface
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit REQUIRED)
-sp_dev_kit_configure_linking(TARGET crypto-sp DEFINES ARM64=1)
-target_link_libraries(crypto-sp PRIVATE ${SP_DEV_KIT_LIBRARIES})
-
-#-------------------------------------------------------------------------------
-# Components that are specific to deployment in the opteesp environment.
-#
-#-------------------------------------------------------------------------------
-add_components(TARGET "crypto-sp"
- BASE_DIR ${TS_ROOT}
- COMPONENTS
- "components/common/tlv"
- "components/common/trace"
- "components/common/utils"
- "components/config/ramstore"
- "components/config/loader/sp"
- "components/messaging/ffa/libsp"
- "components/rpc/ffarpc/endpoint"
- "components/rpc/ffarpc/caller/sp"
- "components/rpc/common/caller"
- "components/rpc/common/interface"
- "components/service/common/include"
- "components/service/common/client"
- "components/service/common/serializer/protobuf"
- "components/service/common/provider"
- "components/service/discovery/provider"
- "components/service/discovery/provider/serializer/packed-c"
- "components/service/crypto/provider"
- "components/service/crypto/provider/serializer/protobuf"
- "components/service/crypto/provider/serializer/packed-c"
- "components/service/crypto/provider/extension/hash"
- "components/service/crypto/provider/extension/hash/serializer/packed-c"
- "components/service/crypto/provider/extension/cipher"
- "components/service/crypto/provider/extension/cipher/serializer/packed-c"
- "components/service/crypto/provider/extension/key_derivation"
- "components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
- "components/service/crypto/provider/extension/mac"
- "components/service/crypto/provider/extension/mac/serializer/packed-c"
- "components/service/crypto/factory/full"
- "components/service/crypto/backend/mbedcrypto"
- "components/service/crypto/backend/mbedcrypto/trng_adapter/platform"
- "components/service/secure_storage/include"
- "components/service/secure_storage/frontend/psa/its"
- "components/service/secure_storage/backend/secure_storage_client"
- "components/service/secure_storage/backend/null_store"
- "components/service/secure_storage/factory/sp/rot_store"
- "protocols/rpc/common/packed-c"
- "protocols/service/secure_storage/packed-c"
- "protocols/service/crypto/protobuf"
- "environments/opteesp"
-)
-
-target_sources(crypto-sp PRIVATE
- crypto_sp.c
-)
-
-#-------------------------------------------------------------------------------
-# Set target platform to provide drivers needed by the deployment
-#
-#-------------------------------------------------------------------------------
-add_platform(TARGET "crypto-sp")
-
-#-------------------------------------------------------------------------------
-# Components used from external projects
-#
-#-------------------------------------------------------------------------------
-
-# Nanopb
-list(APPEND NANOPB_EXTERNAL_INCLUDE_PATHS ${SP_DEV_KIT_INCLUDE_DIR})
-include(../../../external/nanopb/nanopb.cmake)
-target_link_libraries(crypto-sp PRIVATE nanopb::protobuf-nanopb-static)
-protobuf_generate_all(TGT "crypto-sp" NAMESPACE "protobuf" BASE_DIR "${TS_ROOT}/protocols")
-
-# Mbed TLS provides libmbedcrypto
-list(APPEND MBEDTLS_EXTRA_INCLUDES ${SP_DEV_KIT_INCLUDE_DIR})
-set(MBEDTLS_EXTRA_INCLUDES ${MBEDTLS_EXTRA_INCLUDES}
- CACHE STRING "PSA ITS for Mbed TLS" FORCE)
-include(../../../external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(crypto-sp PRIVATE mbedcrypto)
-
-if(CMAKE_CROSSCOMPILING)
- target_link_libraries(crypto-sp PRIVATE stdc++ gcc m)
-endif()
-
-#################################################################
-
-target_compile_definitions(crypto-sp PRIVATE
- ARM64=1
-)
-
-target_include_directories(crypto-sp PRIVATE
- ${TS_ROOT}
- ${TS_ROOT}/components
- ${TS_ROOT}/deployments/crypto/opteesp
-)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_compile_options(crypto-sp PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
- -std=c99
- )
-
- # Options for GCC that control linking
- target_link_options(crypto-sp PRIVATE
- -zmax-page-size=4096
- )
- # Options directly for LD, these are not understood by GCC
- target_link_options(crypto-sp PRIVATE
- -Wl,--as-needed
- -Wl,--sort-section=alignment
- # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
- )
-endif()
-
-compiler_generate_stripped_elf(TARGET crypto-sp NAME "${SP_UUID}.stripped.elf" RES STRIPPED_ELF)
-
-######################################## install
-if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
-endif()
-#TODO: api headers
-
-install(TARGETS crypto-sp
- PUBLIC_HEADER DESTINATION ${TS_ENV}/include
- RUNTIME DESTINATION ${TS_ENV}/bin
- )
-install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
-
-get_property(_PROTO_FILES TARGET crypto-sp PROPERTY PROTOBUF_FILES)
-install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
-
-
-set(EXPORT_SP_NAME "crypto")
-set(EXPORT_SP_UUID ${SP_UUID})
-include(${TS_ROOT}/environments/opteesp/ExportSp.cmake)
diff --git a/deployments/crypto/opteesp/crypto_sp.c b/deployments/crypto/opteesp/crypto_sp.c
deleted file mode 100644
index ce236d9b4..000000000
--- a/deployments/crypto/opteesp/crypto_sp.c
+++ /dev/null
@@ -1,96 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- */
-
-
-#include <rpc/ffarpc/endpoint/ffarpc_call_ep.h>
-#include <service/secure_storage/factory/storage_factory.h>
-#include <service/crypto/factory/crypto_provider_factory.h>
-#include <service/crypto/backend/mbedcrypto/mbedcrypto_backend.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <config/ramstore/config_ramstore.h>
-#include <config/loader/sp/sp_config_loader.h>
-#include <ffa_api.h>
-#include <sp_api.h>
-#include <sp_messaging.h>
-#include <sp_rxtx.h>
-#include <trace.h>
-
-
-uint16_t own_id = 0; /* !!Needs refactoring as parameter to ffarpc_caller_init */
-
-
-static int sp_init(uint16_t *own_sp_id);
-
-void __noreturn sp_main(struct ffa_init_info *init_info)
-{
- struct crypto_provider *crypto_provider;
- struct ffa_call_ep ffarpc_call_ep;
- struct rpc_interface *crypto_iface;
- struct sp_msg req_msg = { 0 };
- struct sp_msg resp_msg = { 0 };
- struct storage_backend *storage_backend;
-
- /* Boot phase */
- if (sp_init(&own_id) != 0) goto fatal_error;
-
- config_ramstore_init();
- sp_config_load(init_info);
-
- /* Create a storage backend for persistent key storage - prefer ITS */
- storage_backend = storage_factory_create(storage_factory_security_class_INTERNAL_TRUSTED);
- if (!storage_backend) goto fatal_error;
-
- /* Initialize the crypto service */
- crypto_iface = NULL;
-
- if (mbedcrypto_backend_init(storage_backend, 0) == PSA_SUCCESS) {
-
- crypto_provider = crypto_provider_factory_create();
- crypto_iface = service_provider_get_rpc_interface(&crypto_provider->base_provider);
- }
-
- ffa_call_ep_init(&ffarpc_call_ep, crypto_iface);
-
- /* End of boot phase */
- sp_msg_wait(&req_msg);
-
- while (1) {
- ffa_call_ep_receive(&ffarpc_call_ep, &req_msg, &resp_msg);
-
- resp_msg.source_id = req_msg.destination_id;
- resp_msg.destination_id = req_msg.source_id;
-
- sp_msg_send_direct_resp(&resp_msg, &req_msg);
- }
-
-fatal_error:
- /* SP is not viable */
- EMSG("Crypto SP error");
- while (1) {}
-}
-
-void sp_interrupt_handler(uint32_t interrupt_id)
-{
- (void)interrupt_id;
-}
-
-static int sp_init(uint16_t *own_sp_id)
-{
- int status = -1;
- ffa_result ffa_res;
- sp_result sp_res;
- static uint8_t tx_buffer[4096] __aligned(4096);
- static uint8_t rx_buffer[4096] __aligned(4096);
-
- sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
- if (sp_res == SP_RESULT_OK) {
- ffa_res = ffa_id_get(own_sp_id);
- if (ffa_res == FFA_OK) {
- status = 0;
- }
- }
-
- return status;
-}
diff --git a/deployments/crypto/opteesp/crypto_sp.h b/deployments/crypto/opteesp/crypto_sp.h
deleted file mode 100644
index 73aae18c0..000000000
--- a/deployments/crypto/opteesp/crypto_sp.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef CRYPTO_SP_H
-#define CRYPTO_SP_H
-
-#define CRYPTO_SP_UUID \
- {0xd9df52d5, 0x16a2, 0x4bb2, \
- {0x9a, 0xa4, 0xd2, 0x6d, 0x3b, 0x84, 0xe8, 0xc0}}
-
-#define CRYPTO_SP_UUID_BYTES \
- {0xd9, 0xdf, 0x52, 0xd5, 0x16, 0xa2, 0x4b, 0xb2, \
- 0x9a, 0xa4, 0xd2, 0x6d, 0x3b, 0x84, 0xe8, 0xc0}
-
-#endif /* CRYPTO_SP_H */
diff --git a/deployments/crypto/opteesp/optee_sp_user_defines.h b/deployments/crypto/opteesp/optee_sp_user_defines.h
deleted file mode 100644
index 88e1adc82..000000000
--- a/deployments/crypto/opteesp/optee_sp_user_defines.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_HEADER_DEFINES_H
-#define SP_HEADER_DEFINES_H
-
-/* To get UUID definition */
-#include "crypto_sp.h"
-
-#define OPTEE_SP_UUID CRYPTO_SP_UUID
-#define OPTEE_SP_FLAGS 0
-
-/* Provisioned stack size */
-#define OPTEE_SP_STACK_SIZE (64 * 1024)
-
-/* Provisioned heap size */
-#define OPTEE_SP_HEAP_SIZE (480 * 1024)
-
-#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/deployment.cmake b/deployments/deployment.cmake
index e1aaed033..76b0f1832 100644
--- a/deployments/deployment.cmake
+++ b/deployments/deployment.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -55,4 +55,25 @@ set(TS_PLATFORM ${_default_platform} CACHE STRING "Selected platform")
define_property(TARGET PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
BRIEF_DOCS "List of platform driver interfaces used for a deployment."
FULL_DOCS "Used by the platform specific builder to specify a configuration for the built platform components."
- ) \ No newline at end of file
+ )
+
+# Set default build type to Debug
+if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type.")
+endif()
+
+# List of supported build types. Needs to be in alignment with the toolchain file
+set(TS_SUPPORTED_BUILD_TYPES DEBUG "MINSIZEREL" "MINSIZWITHDEBINFO" "RELEASE" "RELWITHDEBINFO" CACHE
+ STRING "List of supported build types.")
+
+# Convert the build type string to upper case to help case insensitive comparison.
+string(TOUPPER "${CMAKE_BUILD_TYPE}" UC_CMAKE_BUILD_TYPE CACHE STRING "Easy to compare build type.")
+mark_as_advanced(UC_CMAKE_BUILD_TYPE)
+
+# Validate build type
+if (NOT "${UC_CMAKE_BUILD_TYPE}" IN_LIST TS_SUPPORTED_BUILD_TYPES)
+ message(FATAL_ERROR "Unknown build type \"${CMAKE_BUILD_TYPE}\" specified in CMAKE_BUILD_TYPE.")
+endif()
+
+# Default protocol UUID used by TS SPs.
+set(TS_RPC_UUID_CANON "bdcd76d7-825e-4751-963b-86d4f84943ac" CACHE STRING "Trusted Services PRC (protocol) UUID.")
diff --git a/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/CMakeLists.txt b/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..00d371745
--- /dev/null
+++ b/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/CMakeLists.txt
@@ -0,0 +1,98 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the env-test deployment for opteesp
+#
+# Builds the test_runner service provider with a set of baremetal drivers
+# and test cases for testing drivers from within an SEL0 SP.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(env-test)
+target_include_directories(env-test PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "33c75baf-ac6a-4fe4-8ac7-e9909bee2d17")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "ENVTEST" CACHE STRING "Trace prefix")
+
+target_include_directories(env-test PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Deployment specific components
+# External project source-level dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET "env-test")
+
+#-------------------------------------------------------------------------------
+# Defines environment and test suites for env-test deployment
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "env-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/env_test_sp.cmake REQUIRED)
+include(../../env-test.cmake REQUIRED)
+include(../../suites/baremetal-tests.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET env-test)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(env-test PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(env-test PRIVATE
+ -std=c99
+ )
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+#TODO: api headers
+
+install(TARGETS env-test
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+get_property(_PROTO_FILES TARGET env-test PROPERTY PROTOBUF_FILES)
+install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "env-test"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_env-test.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/default_env-test.dts.in b/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/default_env-test.dts.in
new file mode 100644
index 000000000..9c09689cf
--- /dev/null
+++ b/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/default_env-test.dts.in
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "EnvTest";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ /* Without optional base-address */
+ test-memory {
+ description = "test-memory";
+ pages-count = <4>;
+ attributes = <0x7>; /* read-write-execute */
+ };
+ };
+
+ device-regions {
+ compatible = "arm,ffa-manifest-device-regions";
+
+ trng {
+ /* Armv8 A Foundation Platform values */
+ base-address = <0x00000000 0x7fe60000>;
+ pages-count = <1>;
+ attributes = <0x3>; /* read-write */
+ };
+ };
+
+ boot-params {
+ compatible = "arm,ffa-manifest-boot-params";
+
+ /* Legacy node to keep compatibility with psa-development SPMC. */
+ event-log {
+ param = "EVENT_LOG"; /* The init parameter name */
+ tag = "arm,event-log"; /* Object identifier */
+ };
+ };
+
+ tpm_event_log {
+ compatible = "arm,tpm_event_log";
+ tpm_event_log_addr = <0x0 0x0>;
+ tpm_event_log_size = <0x0>;
+ };
+};
diff --git a/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/optee_sp_user_defines.h b/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..ebc7dada8
--- /dev/null
+++ b/deployments/env-test/config/baremetal-fvp_base_revc-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/env-test/config/baremetal-fvp_base_revc-sp/CMakeLists.txt b/deployments/env-test/config/baremetal-fvp_base_revc-sp/CMakeLists.txt
new file mode 100644
index 000000000..9fa79740b
--- /dev/null
+++ b/deployments/env-test/config/baremetal-fvp_base_revc-sp/CMakeLists.txt
@@ -0,0 +1,97 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the env-test deployment for sp
+#
+# Builds the test_runner service provider with a set of baremetal drivers
+# and test cases for testing drivers from within an SEL0 SP.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(env-test)
+target_include_directories(env-test PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_NAME "env-test")
+set(SP_BIN_UUID_CANON "33c75baf-ac6a-4fe4-8ac7-e9909bee2d17")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(TRACE_PREFIX "ENVTEST" CACHE STRING "Trace prefix")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the opteesp environment.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "env-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+#-------------------------------------------------------------------------------
+# Component configuration specific and common components
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET "env-test")
+
+include(../../env/commonsp/env_test_sp.cmake REQUIRED)
+include(../../env-test.cmake REQUIRED)
+include(../../suites/baremetal-tests.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "env-test")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(env-test PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(env-test PRIVATE
+ -std=c99
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET env-test NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET env-test NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS env-test
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake REQUIRED)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/env-test/opteesp/default_env-test.dts.in b/deployments/env-test/config/baremetal-fvp_base_revc-sp/default_env-test.dts.in
index f64a5faf8..8c741b29c 100644
--- a/deployments/env-test/opteesp/default_env-test.dts.in
+++ b/deployments/env-test/config/baremetal-fvp_base_revc-sp/default_env-test.dts.in
@@ -1,11 +1,9 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-
@DTS_TAG@
-
@DTS_NODE@ {
compatible = "arm,ffa-manifest-1.0";
ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
@@ -15,11 +13,11 @@
exception-level = <1>; /* S-EL0 */
execution-state = <0>; /* AArch64 */
xlat-granule = <0>; /* 4KiB */
- messaging-method = <0>; /* Direct messaging only */
-
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
memory-regions {
compatible = "arm,ffa-manifest-memory-regions";
-
+ #include "@EXPORT_DTS_MEM_REGIONS@"
/* Without optional base-address */
test-memory {
description = "test-memory";
@@ -27,10 +25,8 @@
attributes = <0x7>; /* read-write-execute */
};
};
-
device-regions {
compatible = "arm,ffa-manifest-device-regions";
-
trng {
/* Armv8 A Foundation Platform values */
base-address = <0x00000000 0x7fe60000>;
@@ -38,10 +34,8 @@
attributes = <0x3>; /* read-write */
};
};
-
boot-params {
compatible = "arm,ffa-manifest-boot-params";
-
event-log {
param = "EVENT_LOG"; /* The init parameter name */
tag = "arm,event-log"; /* Object identifier */
diff --git a/deployments/env-test/opteesp/CMakeLists.txt b/deployments/env-test/config/n1sdp-opteesp/CMakeLists.txt
index d75f74f2b..1ddbcf9d4 100644
--- a/deployments/env-test/opteesp/CMakeLists.txt
+++ b/deployments/env-test/config/n1sdp-opteesp/CMakeLists.txt
@@ -1,14 +1,14 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
# Set default platform.
set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
-include(../../deployment.cmake REQUIRED)
+include(../../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
# The CMakeLists.txt for building the env-test deployment for opteesp
@@ -21,95 +21,53 @@ include(${TS_ROOT}/environments/opteesp/env.cmake)
project(trusted-services LANGUAGES C ASM)
add_executable(env-test)
target_include_directories(env-test PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
-set(SP_UUID "33c75baf-ac6a-4fe4-8ac7-e9909bee2d17")
-set(TRACE_PREFIX "ENVTEST" CACHE STRING "Trace prefix")
+set(SP_BIN_UUID_CANON "33c75baf-ac6a-4fe4-8ac7-e9909bee2d17")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "ENVTEST" CACHE STRING "Trace prefix")
-# Include SP DEV KIT interface
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit REQUIRED)
-sp_dev_kit_configure_linking(TARGET env-test DEFINES ARM64=1)
-target_link_libraries(env-test PRIVATE ${SP_DEV_KIT_LIBRARIES})
+target_include_directories(env-test PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
#-------------------------------------------------------------------------------
-# Components that are env-test specific to deployment in the opteesp
-# environment.
+# Deployment specific components
+#
#-------------------------------------------------------------------------------
+
add_components(TARGET "env-test"
BASE_DIR ${TS_ROOT}
COMPONENTS
- "components/common/trace"
- "components/common/utils"
- "components/config/loader/sp"
- "components/messaging/ffa/libsp"
- "components/rpc/ffarpc/endpoint"
- "components/config/test/sp"
"environments/opteesp"
)
-#-------------------------------------------------------------------------------
-# Extend with components that are common across all deployments of
-# env-test
-#
-#-------------------------------------------------------------------------------
-include(../env_test.cmake REQUIRED)
-
-#-------------------------------------------------------------------------------
-# Deployment specific source files
-#-------------------------------------------------------------------------------
-target_sources(env-test PRIVATE
- env_test.c
- env_test_tests.c
-)
+include(../../env/commonsp/env_test_sp.cmake REQUIRED)
+include(../../env-test.cmake REQUIRED)
+include(../../suites/edk2-platform-tests.cmake REQUIRED)
#-------------------------------------------------------------------------------
# Set target platform to provide drivers needed by the deployment
#
#-------------------------------------------------------------------------------
-add_platform(TARGET "env_test")
-
-if(CMAKE_CROSSCOMPILING)
- target_link_libraries(env-test PRIVATE stdc++ gcc m)
-endif()
-
-#################################################################
+add_platform(TARGET env-test)
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
target_compile_definitions(env-test PRIVATE
ARM64=1
)
-target_include_directories(env-test PRIVATE
- ${TS_ROOT}
- ${TS_ROOT}/components
- ${TS_ROOT}/deployments/env-test/opteesp
-)
-
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_compile_options(env-test PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
- $<$<COMPILE_LANGUAGE:C>:-std=c99>
- $<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>
- )
-
- # Options for GCC that control linking
- target_link_options(env-test PRIVATE
- -zmax-page-size=4096
- )
- # Options directly for LD, these are not understood by GCC
- target_link_options(env-test PRIVATE
- -Wl,--as-needed
- -Wl,--sort-section=alignment
- # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
+ -std=c99
)
endif()
-compiler_generate_stripped_elf(TARGET env-test NAME "${SP_UUID}.stripped.elf" RES STRIPPED_ELF)
-
-######################################## install
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
endif()
@@ -119,12 +77,16 @@ install(TARGETS env-test
PUBLIC_HEADER DESTINATION ${TS_ENV}/include
RUNTIME DESTINATION ${TS_ENV}/bin
)
-install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
get_property(_PROTO_FILES TARGET env-test PROPERTY PROTOBUF_FILES)
install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
-
-set(EXPORT_SP_NAME "env-test")
-set(EXPORT_SP_UUID ${SP_UUID})
-include(${TS_ROOT}/environments/opteesp/ExportSp.cmake)
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "env-test"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_env-test.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/env-test/config/n1sdp-opteesp/default_env-test.dts.in b/deployments/env-test/config/n1sdp-opteesp/default_env-test.dts.in
new file mode 100644
index 000000000..9c09689cf
--- /dev/null
+++ b/deployments/env-test/config/n1sdp-opteesp/default_env-test.dts.in
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "EnvTest";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ /* Without optional base-address */
+ test-memory {
+ description = "test-memory";
+ pages-count = <4>;
+ attributes = <0x7>; /* read-write-execute */
+ };
+ };
+
+ device-regions {
+ compatible = "arm,ffa-manifest-device-regions";
+
+ trng {
+ /* Armv8 A Foundation Platform values */
+ base-address = <0x00000000 0x7fe60000>;
+ pages-count = <1>;
+ attributes = <0x3>; /* read-write */
+ };
+ };
+
+ boot-params {
+ compatible = "arm,ffa-manifest-boot-params";
+
+ /* Legacy node to keep compatibility with psa-development SPMC. */
+ event-log {
+ param = "EVENT_LOG"; /* The init parameter name */
+ tag = "arm,event-log"; /* Object identifier */
+ };
+ };
+
+ tpm_event_log {
+ compatible = "arm,tpm_event_log";
+ tpm_event_log_addr = <0x0 0x0>;
+ tpm_event_log_size = <0x0>;
+ };
+};
diff --git a/deployments/env-test/config/n1sdp-opteesp/optee_sp_user_defines.h b/deployments/env-test/config/n1sdp-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..ebc7dada8
--- /dev/null
+++ b/deployments/env-test/config/n1sdp-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/env-test/env_test.cmake b/deployments/env-test/env-test.cmake
index 87a329857..c81810cb2 100644
--- a/deployments/env-test/env_test.cmake
+++ b/deployments/env-test/env-test.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -20,33 +20,18 @@ add_components(
BASE_DIR ${TS_ROOT}
COMPONENTS
"components/common/tlv"
- "components/config/ramstore"
"components/rpc/common/interface"
- "components/rpc/common/caller"
"components/service/common/include"
- "components/service/common/client"
"components/service/common/provider"
"components/service/test_runner/provider"
"components/service/test_runner/provider/serializer/packed-c"
"components/service/test_runner/provider/backend/null"
"components/service/test_runner/provider/backend/simple_c"
- "components/service/crypto/backend/mbedcrypto"
- "components/service/crypto/backend/mbedcrypto/trng_adapter/platform"
- "components/service/crypto/backend/mbedcrypto/trng_adapter/test"
- "components/service/secure_storage/include"
- "components/service/secure_storage/frontend/psa/its"
- "components/service/secure_storage/backend/secure_storage_client"
"protocols/rpc/common/packed-c"
)
-#-------------------------------------------------------------------------------
-# Components used from external projects
-#
-#-------------------------------------------------------------------------------
+target_include_directories(env-test PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
-# Mbed TLS provides libmbedcrypto
-list(APPEND MBEDTLS_EXTRA_INCLUDES ${SP_DEV_KIT_INCLUDE_DIR})
-set(MBEDTLS_EXTRA_INCLUDES ${MBEDTLS_EXTRA_INCLUDES}
- CACHE STRING "PSA ITS for Mbed TLS" FORCE)
-include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(env-test PRIVATE mbedcrypto)
diff --git a/deployments/env-test/env/commonsp/env_test_sp.c b/deployments/env-test/env/commonsp/env_test_sp.c
new file mode 100644
index 000000000..daaf50a74
--- /dev/null
+++ b/deployments/env-test/env/commonsp/env_test_sp.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h"
+#include "service/test_runner/provider/test_runner_provider.h"
+#include "service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "config/ramstore/config_ramstore.h"
+#include "config/loader/sp/sp_config_loader.h"
+#include "ffa_api.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+#include "deployments/env-test/suites/registration/env_test_register.h"
+
+static bool sp_init(uint16_t *own_sp_id);
+
+void __noreturn sp_main(union ffa_boot_info *boot_info)
+{
+ struct test_runner_provider test_runner_provider = { 0 };
+ struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
+ struct rpc_service_interface *test_runner_iface = NULL;
+ struct sp_msg req_msg = { 0 };
+ struct sp_msg resp_msg = { 0 };
+ uint16_t own_id = 0;
+ sp_result result = SP_RESULT_INTERNAL_ERROR;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Boot */
+ if (!sp_init(&own_id)) {
+ EMSG("Failed to init SP");
+ goto fatal_error;
+ }
+
+ config_ramstore_init();
+
+ if (!sp_config_load(boot_info)) {
+ EMSG("Failed to load SP config");
+ goto fatal_error;
+ }
+
+ /* Initialize the test_runner service */
+ test_runner_iface = test_runner_provider_init(&test_runner_provider);
+ if (!test_runner_iface) {
+ EMSG("Failed to initialize test runner provider");
+ goto fatal_error;
+ }
+
+ test_runner_provider_register_serializer(&test_runner_provider,
+ TS_RPC_ENCODING_PACKED_C, packedc_test_runner_provider_serializer_instance());
+
+ env_test_register_tests(&test_runner_provider);
+
+ rpc_status = ts_rpc_endpoint_sp_init(&rpc_endpoint, 1, 16);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to initialize RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, test_runner_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /* End of boot phase */
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ ts_rpc_endpoint_sp_receive(&rpc_endpoint, &req_msg, &resp_msg);
+
+ resp_msg.source_id = req_msg.destination_id;
+ resp_msg.destination_id = req_msg.source_id;
+
+ result = sp_msg_send_direct_resp(&resp_msg, &req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("environment-test SP error");
+ while (1) {}
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
+
+static bool sp_init(uint16_t *own_id)
+{
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ static uint8_t tx_buffer[4096] __aligned(4096);
+ static uint8_t rx_buffer[4096] __aligned(4096);
+
+ sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", sp_res);
+ return false;
+ }
+
+ sp_res = sp_discovery_own_id_get(own_id);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", sp_res);
+ return false;
+ }
+
+ return true;
+}
diff --git a/deployments/env-test/env/commonsp/env_test_sp.cmake b/deployments/env-test/env/commonsp/env_test_sp.cmake
new file mode 100644
index 000000000..d5ee2450d
--- /dev/null
+++ b/deployments/env-test/env/commonsp/env_test_sp.cmake
@@ -0,0 +1,31 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the env-test service provider
+# within a secure partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for env-test sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "env-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/common/interface"
+ "components/rpc/common/endpoint"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/endpoint/sp"
+)
+
+target_sources(env-test PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/env_test_sp.c
+)
diff --git a/deployments/env-test/env/commonsp/env_test_sp.h b/deployments/env-test/env/commonsp/env_test_sp.h
new file mode 100644
index 000000000..4fd979202
--- /dev/null
+++ b/deployments/env-test/env/commonsp/env_test_sp.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ENV_TEST_H
+#define ENV_TEST_H
+
+#endif /* ENV_TEST_H */
diff --git a/deployments/env-test/opteesp/.gitignore b/deployments/env-test/opteesp/.gitignore
deleted file mode 100644
index 378eac25d..000000000
--- a/deployments/env-test/opteesp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-build
diff --git a/deployments/env-test/opteesp/env_test.c b/deployments/env-test/opteesp/env_test.c
deleted file mode 100644
index 78c439fc1..000000000
--- a/deployments/env-test/opteesp/env_test.c
+++ /dev/null
@@ -1,92 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#include <rpc/ffarpc/caller/sp/ffarpc_caller.h>
-#include <rpc/ffarpc/endpoint/ffarpc_call_ep.h>
-#include <service/test_runner/provider/test_runner_provider.h>
-#include <service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.h>
-#include <protocols/rpc/common/packed-c/status.h>
-#include <config/ramstore/config_ramstore.h>
-#include <config/loader/sp/sp_config_loader.h>
-#include <ffa_api.h>
-#include <sp_api.h>
-#include <sp_rxtx.h>
-#include <trace.h>
-#include "env_test_tests.h"
-
-
-uint16_t own_id = 0; /* !!Needs refactoring as parameter to ffarpc_caller_init */
-
-
-static int sp_init(uint16_t *own_sp_id);
-
-void __noreturn sp_main(struct ffa_init_info *init_info)
-{
- struct test_runner_provider test_runner_provider;
- struct ffa_call_ep ffarpc_call_ep;
- struct rpc_interface *test_runner_iface;
- struct ffarpc_caller ffarpc_caller;
- struct sp_msg req_msg;
-
- /* Boot */
- if (sp_init(&own_id) != 0) goto fatal_error;
-
- config_ramstore_init();
- sp_config_load(init_info);
-
- /* Initialize the test_runner service */
- test_runner_iface = test_runner_provider_init(&test_runner_provider);
-
- test_runner_provider_register_serializer(&test_runner_provider,
- TS_RPC_ENCODING_PACKED_C, packedc_test_runner_provider_serializer_instance());
-
- env_test_register_tests(&test_runner_provider);
-
- ffa_call_ep_init(&ffarpc_call_ep, test_runner_iface);
-
- /* End of boot phase */
- sp_msg_wait(&req_msg);
-
- while (1) {
-
- struct sp_msg resp_msg;
-
- ffa_call_ep_receive(&ffarpc_call_ep, &req_msg, &resp_msg);
-
- resp_msg.source_id = req_msg.destination_id;
- resp_msg.destination_id = req_msg.source_id;
-
- sp_msg_send_direct_resp(&resp_msg, &req_msg);
- }
-
-fatal_error:
- /* SP is not viable */
- EMSG("environment-test SP error");
- while (1) {}
-}
-
-void sp_interrupt_handler(uint32_t interrupt_id)
-{
- (void)interrupt_id;
-}
-
-static int sp_init(uint16_t *own_sp_id)
-{
- int status = -1;
- ffa_result ffa_res;
- sp_result sp_res;
- static uint8_t tx_buffer[4096] __aligned(4096);
- static uint8_t rx_buffer[4096] __aligned(4096);
-
- sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
- if (sp_res == SP_RESULT_OK) {
- ffa_res = ffa_id_get(own_sp_id);
- if (ffa_res == FFA_OK) {
- status = 0;
- }
- }
-
- return status;
-}
diff --git a/deployments/env-test/opteesp/env_test.h b/deployments/env-test/opteesp/env_test.h
deleted file mode 100644
index 0f4c8b789..000000000
--- a/deployments/env-test/opteesp/env_test.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef ENV_TEST_SP_H
-#define ENV_TEST_SP_H
-
-#define ENV_TEST_SP_UUID \
- {0x33c75baf, 0xac6a, 0x4fe4, \
- {0x8a, 0xc7, 0xe9, 0x90, 0x9b, 0xee, 0x2d, 0x17}}
-
-#define ENV_TEST_SP_UUID_BYTES \
- {0x33, 0xc7, 0x5b, 0xaf, 0xac, 0x6a, 0x4f, 0xef, \
- 0x8a, 0xcy, 0xe9, 0x90, 0x9b, 0xee, 0x2d, 0x17}
-
-#endif /* ENV_TEST_SP_H */
diff --git a/deployments/env-test/opteesp/optee_sp_user_defines.h b/deployments/env-test/opteesp/optee_sp_user_defines.h
deleted file mode 100644
index a524a6e46..000000000
--- a/deployments/env-test/opteesp/optee_sp_user_defines.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_HEADER_DEFINES_H
-#define SP_HEADER_DEFINES_H
-
-/* To get UUID definition */
-#include "env_test.h"
-
-#define OPTEE_SP_UUID ENV_TEST_SP_UUID
-#define OPTEE_SP_FLAGS 0
-
-/* Provisioned stack size */
-#define OPTEE_SP_STACK_SIZE (64 * 1024)
-
-/* Provisioned heap size */
-#define OPTEE_SP_HEAP_SIZE (32 * 1024)
-
-#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/env-test/suites/baremetal-tests.cmake b/deployments/env-test/suites/baremetal-tests.cmake
new file mode 100644
index 000000000..98588a714
--- /dev/null
+++ b/deployments/env-test/suites/baremetal-tests.cmake
@@ -0,0 +1,51 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Baremetal driver test cases to test paltform driver operation from within
+# a secure execution environment.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Components-under-test and test cases baremetal platform tests.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "env-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/uuid"
+ "components/service/crypto/backend/mbedcrypto"
+ "components/service/crypto/backend/mbedcrypto/trng_adapter/platform"
+ "components/service/crypto/backend/mbedcrypto/trng_adapter/test"
+ "components/service/secure_storage/include"
+ "components/service/secure_storage/frontend/psa/its"
+ "components/service/secure_storage/backend/secure_storage_client"
+ "components/config/test/sp"
+ "components/rpc/common/caller"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/semihosting"
+ "components/service/block_storage/block_store/device/semihosting/test"
+)
+
+target_sources(env-test PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/registration/baremetal_tests.c
+)
+
+#-------------------------------------------------------------------------------
+# Components used from external projects
+#
+#-------------------------------------------------------------------------------
+
+# Mbed TLS provides libmbedcrypto
+set(MBEDTLS_USER_CONFIG_FILE "${TS_ROOT}/external/MbedTLS/config/libmbed_only.h"
+ CACHE STRING "Configuration file for Mbed TLS" FORCE)
+include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
+target_link_libraries(env-test PRIVATE MbedTLS::mbedcrypto)
+
+#-------------------------------------------------------------------------------
+# This test suite depends on platform specific drivers
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "env-test")
diff --git a/deployments/env-test/suites/edk2-platform-tests.cmake b/deployments/env-test/suites/edk2-platform-tests.cmake
new file mode 100644
index 000000000..dab56edba
--- /dev/null
+++ b/deployments/env-test/suites/edk2-platform-tests.cmake
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Test for drivers reused from edk2-platforms
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Components-under-test and test cases edk2 platform tests.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "env-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/config/test/sp"
+)
+
+target_sources(env-test PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/registration/edk2_platform_tests.c
+)
+
+#-------------------------------------------------------------------------------
+# This test suite depends on platform specific drivers
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "env-test") \ No newline at end of file
diff --git a/deployments/env-test/suites/registration/baremetal_tests.c b/deployments/env-test/suites/registration/baremetal_tests.c
new file mode 100644
index 000000000..d7695a540
--- /dev/null
+++ b/deployments/env-test/suites/registration/baremetal_tests.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <service/test_runner/provider/backend/simple_c/simple_c_test_runner.h>
+#include <config/test/sp/sp_config_tests.h>
+#include <service/crypto/backend/mbedcrypto/trng_adapter/test/trng_env_tests.h>
+#include <service/block_storage/block_store/device/semihosting/test/sh_block_store_tests.h>
+
+/**
+ * Register tests that constitute the 'baremetal-tests' suite. Used for testing
+ * platform drivers that conform to the 'baremetal' driver model.
+ */
+void env_test_register_tests(struct test_runner_provider *context)
+{
+ simple_c_test_runner_init(context);
+
+ sp_config_tests_register();
+ trng_env_tests_register();
+ sh_block_store_tests_register();
+}
diff --git a/deployments/env-test/opteesp/env_test_tests.c b/deployments/env-test/suites/registration/edk2_platform_tests.c
index 11c1f420a..7b0fa449a 100644
--- a/deployments/env-test/opteesp/env_test_tests.c
+++ b/deployments/env-test/suites/registration/edk2_platform_tests.c
@@ -1,16 +1,18 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
*/
#include <service/test_runner/provider/backend/simple_c/simple_c_test_runner.h>
#include <config/test/sp/sp_config_tests.h>
-#include <service/crypto/backend/mbedcrypto/trng_adapter/test/trng_env_tests.h>
+/**
+ * Register tests that constitute the 'edk2-platform-tests' suite. Used for testing
+ * platform drivers that conform to the 'edk2 (UEFI)' driver model.
+ */
void env_test_register_tests(struct test_runner_provider *context)
{
simple_c_test_runner_init(context);
sp_config_tests_register();
- trng_env_tests_register();
}
diff --git a/deployments/env-test/opteesp/env_test_tests.h b/deployments/env-test/suites/registration/env_test_register.h
index 305fc4547..d455f5af4 100644
--- a/deployments/env-test/opteesp/env_test_tests.h
+++ b/deployments/env-test/suites/registration/env_test_register.h
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef ENV_TEST_TESTS_H
-#define ENV_TEST_TESTS_H
+#ifndef ENV_TEST_REGISTER_H
+#define ENV_TEST_REGISTER_H
struct test_runner_provider;
@@ -15,4 +15,4 @@ struct test_runner_provider;
void env_test_register_tests(struct test_runner_provider *context);
-#endif /* ENV_TEST_TESTS_H */
+#endif /* ENV_TEST_REGISTER_H */
diff --git a/deployments/fwu-tool/file-block-store.cmake b/deployments/fwu-tool/file-block-store.cmake
new file mode 100644
index 000000000..ea1590bbc
--- /dev/null
+++ b/deployments/fwu-tool/file-block-store.cmake
@@ -0,0 +1,33 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Lists components that provide an infrastructure layer for the block-storage
+# service provider that uses a ram-backed block store, partitioned by default
+# using the 'ref' configuration. This infrastructure is intended for test
+# purposes.
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "Mandatory parameter TGT is not defined.")
+endif()
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET ${TGT}
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/media/disk"
+ "components/media/volume"
+ "components/media/volume/base_io_dev"
+ "components/media/volume/block_volume"
+ "components/media/volume/factory/single_flash"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/file"
+ "components/service/block_storage/block_store/partitioned"
+ "components/service/block_storage/factory/file"
+ "components/service/block_storage/config/gpt"
+) \ No newline at end of file
diff --git a/deployments/fwu-tool/fwu.cmake b/deployments/fwu-tool/fwu.cmake
new file mode 100644
index 000000000..d9cac39ce
--- /dev/null
+++ b/deployments/fwu-tool/fwu.cmake
@@ -0,0 +1,55 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Common components used for any deployment of the fwu service provider.
+#-------------------------------------------------------------------------------
+
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "Mandatory parameter TGT is not defined.")
+endif()
+
+#-------------------------------------------------------------------------------
+# Components common to all deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET ${TGT}
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/app/fwu-tool"
+ "components/common/uuid"
+ "components/common/endian"
+ "components/media/disk/gpt_iterator"
+ "components/media/volume/index"
+ "components/service/common/include"
+ "components/service/fwu/agent"
+ "components/service/fwu/config"
+ "components/service/fwu/config/gpt"
+ "components/service/fwu/fw_store/banked"
+ "components/service/fwu/fw_store/banked/metadata_serializer/v1"
+ "components/service/fwu/fw_store/banked/metadata_serializer/v2"
+ "components/service/fwu/installer"
+ "components/service/fwu/installer/raw"
+ "components/service/fwu/installer/copy"
+ "components/service/fwu/installer/factory/default"
+ "components/service/fwu/inspector/direct"
+)
+
+#################################################################
+
+target_include_directories(${TGT} PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
+
+#-------------------------------------------------------------------------------
+# Define install content.
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS ${TGT}
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include)
diff --git a/deployments/fwu-tool/linux-pc/CMakeLists.txt b/deployments/fwu-tool/linux-pc/CMakeLists.txt
new file mode 100644
index 000000000..e0948c0f9
--- /dev/null
+++ b/deployments/fwu-tool/linux-pc/CMakeLists.txt
@@ -0,0 +1,59 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+include(../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the fwu-tool deployment for linux-pc
+#
+# This configuration builds the FWU update agent into a command-line app
+# that can be used to apply updates to disk image files.
+#-------------------------------------------------------------------------------
+project(trusted-services LANGUAGES CXX C)
+add_executable(fwu-tool)
+set(TGT "fwu-tool")
+target_include_directories(fwu-tool PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+#-------------------------------------------------------------------------------
+# Configure trace output for command-line app
+#
+#-------------------------------------------------------------------------------
+set(TRACE_PREFIX "fwu-tool" CACHE STRING "Trace prefix")
+set(TRACE_LEVEL "TRACE_LEVEL_DEBUG" CACHE STRING "Trace level")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build configuration
+#
+#-------------------------------------------------------------------------------
+
+# Scale number of partitions for pretty complicated fw images
+target_compile_definitions(${TGT} PRIVATE
+ PARTITIONED_BLOCK_STORE_MAX_PARTITIONS=24)
+
+#-------------------------------------------------------------------------------
+# This configuration builds for linux-pc
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/linux-pc/env.cmake)
+add_components(TARGET ${TGT}
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS "environments/linux-pc"
+)
+
+#-------------------------------------------------------------------------------
+# External project source-level dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET ${TGT})
+
+#-------------------------------------------------------------------------------
+# Deployment specific components
+#
+#-------------------------------------------------------------------------------
+include(../fwu.cmake REQUIRED)
+include(../file-block-store.cmake REQUIRED)
diff --git a/deployments/fwu/config/default-opteesp/CMakeLists.txt b/deployments/fwu/config/default-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..f5087d81e
--- /dev/null
+++ b/deployments/fwu/config/default-opteesp/CMakeLists.txt
@@ -0,0 +1,96 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the default fwu deployment for opteesp
+#
+# Builds the fwu service provider for running in an SEL0 secure partition
+# hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(fwu)
+target_include_directories(fwu PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "6823a838-1b06-470e-9774-0cce8bfb53fd")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+
+target_include_directories(fwu PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Configure trace output
+#
+#-------------------------------------------------------------------------------
+set(TRACE_PREFIX "FWU" CACHE STRING "Trace prefix")
+set(TRACE_LEVEL "TRACE_LEVEL_DEBUG" CACHE STRING "Trace level")
+
+#-------------------------------------------------------------------------------
+# Deployment specific components
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "fwu"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/fwu_sp.cmake REQUIRED)
+include(../../infra/semihosted-block-store.cmake REQUIRED)
+include(../../fwu.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "fwu")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(fwu PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(fwu PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+#TODO: api headers
+
+install(TARGETS fwu
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+get_property(_PROTO_FILES TARGET fwu PROPERTY PROTOBUF_FILES)
+install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "fwu"
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_fwu.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/fwu/config/default-opteesp/default_fwu.dts.in b/deployments/fwu/config/default-opteesp/default_fwu.dts.in
new file mode 100644
index 000000000..14970d592
--- /dev/null
+++ b/deployments/fwu/config/default-opteesp/default_fwu.dts.in
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "FWU";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/fwu/config/default-opteesp/optee_sp_user_defines.h b/deployments/fwu/config/default-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..e5fb8c185
--- /dev/null
+++ b/deployments/fwu/config/default-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/fwu/config/default-sp/CMakeLists.txt b/deployments/fwu/config/default-sp/CMakeLists.txt
new file mode 100644
index 000000000..f84ba8f27
--- /dev/null
+++ b/deployments/fwu/config/default-sp/CMakeLists.txt
@@ -0,0 +1,97 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the fwu deployment for generic sp
+# environment.
+#
+# Builds the fwu service provider for running in an SEL0 secure
+# partition hosted by any SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(fwu)
+target_include_directories(fwu PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_NAME "fwu")
+set(SP_BIN_UUID_CANON "6823a838-1b06-470e-9774-0cce8bfb53fd")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+
+#-------------------------------------------------------------------------------
+# Configure trace output
+#
+#-------------------------------------------------------------------------------
+set(TRACE_PREFIX "FWU" CACHE STRING "Trace prefix")
+set(TRACE_LEVEL "TRACE_LEVEL_DEBUG" CACHE STRING "Trace level")
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the sp environment.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "fwu"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+include(../../env/commonsp/fwu_sp.cmake REQUIRED)
+include(../../infra/semihosted-block-store.cmake REQUIRED)
+include(../../fwu.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "fwu")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(fwu PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(fwu PRIVATE
+ -std=c99
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET fwu NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET fwu NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS fwu
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/fwu/config/default-sp/default_fwu.dts.in b/deployments/fwu/config/default-sp/default_fwu.dts.in
new file mode 100644
index 000000000..3f1292e1f
--- /dev/null
+++ b/deployments/fwu/config/default-sp/default_fwu.dts.in
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "FWU";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ #include "@EXPORT_DTS_MEM_REGIONS@"
+ };
+};
diff --git a/deployments/fwu/env/commonsp/fwu_sp.c b/deployments/fwu/env/commonsp/fwu_sp.c
new file mode 100644
index 000000000..e3e054404
--- /dev/null
+++ b/deployments/fwu/env/commonsp/fwu_sp.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <stddef.h>
+
+#include "common/crc32/crc32.h"
+#include "config/loader/sp/sp_config_loader.h"
+#include "config/ramstore/config_ramstore.h"
+#include "media/volume/factory/volume_factory.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h"
+#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/config/fwu_configure.h"
+#include "service/fwu/fw_store/banked/bank_scheme.h"
+#include "service/fwu/fw_store/banked/banked_fw_store.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h"
+#include "service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h"
+#include "service/fwu/inspector/direct/direct_fw_inspector.h"
+#include "service/fwu/provider/fwu_provider.h"
+#include "service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_messaging.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+
+/* Set default limit on the number of storage devices to update */
+#ifndef FWU_SP_MAX_STORAGE_DEVICES
+#define FWU_SP_MAX_STORAGE_DEVICES (1)
+#endif
+
+/* Parameters that should be passed forward by the bootloader */
+#define HARD_CODED_BOOT_INDEX (0)
+#define HARD_CODED_METADATA_VER (2)
+
+static bool sp_init(uint16_t *own_sp_id);
+static bool configure_for_platform(void);
+const struct metadata_serializer *select_metadata_serializer(unsigned int version);
+
+void __noreturn sp_main(union ffa_boot_info *boot_info)
+{
+ struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
+ struct fwu_provider service_provider = { 0 };
+ struct rpc_service_interface *service_iface = NULL;
+ struct update_agent update_agent = { 0 };
+ struct fw_store fw_store = { 0 };
+ struct sp_msg req_msg = { 0 };
+ struct sp_msg resp_msg = { 0 };
+ uint16_t own_id = 0;
+ sp_result result = SP_RESULT_INTERNAL_ERROR;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Boot phase */
+ if (!sp_init(&own_id)) {
+ EMSG("Failed to init SP");
+ goto fatal_error;
+ }
+
+ config_ramstore_init();
+
+ if (!sp_config_load(boot_info)) {
+ EMSG("Failed to load SP config");
+ goto fatal_error;
+ }
+
+ crc32_init();
+
+ /* Configuration - discovers required volumes and installers */
+ if (!configure_for_platform()) {
+ EMSG("Failed to configure for platform");
+ goto fatal_error;
+ }
+
+ /* Select FWU metadata serializer for compatibility with bootloader */
+ const struct metadata_serializer *serializer =
+ select_metadata_serializer(HARD_CODED_METADATA_VER);
+
+ if (!serializer) {
+ EMSG("Unsupported FWU metadata version");
+ goto fatal_error;
+ }
+
+ /* Initialise fw store */
+ if (banked_fw_store_init(&fw_store, serializer)) {
+ EMSG("Failed to init fw store");
+ goto fatal_error;
+ }
+
+ if (update_agent_init(&update_agent, HARD_CODED_BOOT_INDEX, direct_fw_inspector_inspect,
+ &fw_store)) {
+ EMSG("Failed to init update agent");
+ goto fatal_error;
+ }
+
+ /* Initialise the FWU service provider */
+ service_iface = fwu_provider_init(&service_provider, &update_agent);
+
+ if (!service_iface) {
+ EMSG("Failed to init service provider");
+ goto fatal_error;
+ }
+
+ fwu_provider_register_serializer(&service_provider, TS_RPC_ENCODING_PACKED_C,
+ packedc_fwu_provider_serializer_instance());
+
+ /* Associate service interface with FFA call endpoint */
+ rpc_status = ts_rpc_endpoint_sp_init(&rpc_endpoint, 1, 16);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to initialize RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, service_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /* End of boot phase */
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ ts_rpc_endpoint_sp_receive(&rpc_endpoint, &req_msg, &resp_msg);
+
+ result = sp_msg_send_direct_resp(&resp_msg, &req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("FWU SP error");
+ while (1) {
+ }
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
+
+static bool sp_init(uint16_t *own_id)
+{
+ static uint8_t tx_buffer[4096] __aligned(4096);
+ static uint8_t rx_buffer[4096] __aligned(4096);
+
+ sp_result sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", sp_res);
+ return false;
+ }
+
+ sp_res = sp_discovery_own_id_get(own_id);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", sp_res);
+ return false;
+ }
+
+ return true;
+}
+
+static bool configure_for_platform(void)
+{
+ struct uuid_octets device_uuids[FWU_SP_MAX_STORAGE_DEVICES];
+ size_t num_storage_devices = 0;
+
+ int status =
+ volume_factory_init(device_uuids, FWU_SP_MAX_STORAGE_DEVICES, &num_storage_devices);
+
+ if (status) {
+ EMSG("Failed to init volume factory: %d", status);
+ return false;
+ }
+
+ status = fwu_configure(device_uuids, num_storage_devices);
+
+ if (status) {
+ EMSG("Failed to setup FWU configuration: %d", status);
+ return false;
+ }
+
+ return true;
+}
+
+const struct metadata_serializer *select_metadata_serializer(unsigned int version)
+{
+ if (version == 1)
+ return metadata_serializer_v1();
+
+ if (version == 2)
+ return metadata_serializer_v2();
+
+ return NULL;
+} \ No newline at end of file
diff --git a/deployments/fwu/env/commonsp/fwu_sp.cmake b/deployments/fwu/env/commonsp/fwu_sp.cmake
new file mode 100644
index 000000000..2fd8ca744
--- /dev/null
+++ b/deployments/fwu/env/commonsp/fwu_sp.cmake
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the fwu service provider
+# within a secure partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for fwu sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "fwu"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/common/crc32"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/common/interface"
+ "components/rpc/common/endpoint"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/endpoint/sp"
+ "components/service/common/provider"
+ "components/service/fwu/provider"
+ "components/service/fwu/provider/serializer/packed-c"
+)
+
+target_sources(fwu PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/fwu_sp.c
+)
diff --git a/deployments/fwu/fwu.cmake b/deployments/fwu/fwu.cmake
new file mode 100644
index 000000000..7276360e2
--- /dev/null
+++ b/deployments/fwu/fwu.cmake
@@ -0,0 +1,39 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Common components used for any deployment of the fwu service provider.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Components common to all deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "fwu"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/uuid"
+ "components/common/endian"
+ "components/media/disk/gpt_iterator"
+ "components/media/volume/index"
+ "components/service/common/include"
+ "components/service/fwu/agent"
+ "components/service/fwu/config"
+ "components/service/fwu/config/gpt"
+ "components/service/fwu/fw_store/banked"
+ "components/service/fwu/fw_store/banked/metadata_serializer/v1"
+ "components/service/fwu/fw_store/banked/metadata_serializer/v2"
+ "components/service/fwu/installer"
+ "components/service/fwu/installer/raw"
+ "components/service/fwu/installer/copy"
+ "components/service/fwu/installer/factory/default"
+ "components/service/fwu/inspector/direct"
+)
+
+#################################################################
+
+target_include_directories(fwu PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
diff --git a/deployments/fwu/infra/file-block-store.cmake b/deployments/fwu/infra/file-block-store.cmake
new file mode 100644
index 000000000..d86f7d03e
--- /dev/null
+++ b/deployments/fwu/infra/file-block-store.cmake
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Lists components that provide an infrastructure layer for the block-storage
+# service provider that uses a ram-backed block store, partitioned by default
+# using the 'ref' configuration. This infrastructure is intended for test
+# purposes.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "fwu"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/media/disk"
+ "components/media/volume"
+ "components/media/volume/base_io_dev"
+ "components/media/volume/block_volume"
+ "components/media/volume/factory/single_flash"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/file"
+ "components/service/block_storage/block_store/partitioned"
+ "components/service/block_storage/factory/file"
+ "components/service/block_storage/config/gpt"
+) \ No newline at end of file
diff --git a/deployments/fwu/infra/semihosted-block-store.cmake b/deployments/fwu/infra/semihosted-block-store.cmake
new file mode 100644
index 000000000..5d95077ac
--- /dev/null
+++ b/deployments/fwu/infra/semihosted-block-store.cmake
@@ -0,0 +1,39 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# A fwu infrastructure where there is a flash device dedicated to holding
+# device firmware and FWU metadata. Flash is assumed to be UEFI formated
+# (MBR/GPT) with separate partitions for primary/backup metadata and
+# A/B banks for firmware storage. The flash is actually realized by a file
+# residing on the host machine and is accessed using semihosting. This
+# infrastructure is intended for FVP/Qemu based testing.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# External project source-level dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET "fwu")
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "fwu"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/media/disk"
+ "components/media/volume"
+ "components/media/volume/base_io_dev"
+ "components/media/volume/block_volume"
+ "components/media/volume/factory/single_flash"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/semihosting"
+ "components/service/block_storage/block_store/partitioned"
+ "components/service/block_storage/factory/semihosting"
+ "components/service/block_storage/config/gpt"
+)
diff --git a/deployments/internal-trusted-storage/config/default-opteesp/CMakeLists.txt b/deployments/internal-trusted-storage/config/default-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..bb159422c
--- /dev/null
+++ b/deployments/internal-trusted-storage/config/default-opteesp/CMakeLists.txt
@@ -0,0 +1,88 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the internal-trusted-storage deployment for opteesp
+#
+# Builds the secure storage service provider for running in an SEL0 secure
+# partition hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(internal-trusted-storage)
+target_include_directories(internal-trusted-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "dc1eef48-b17a-4ccf-ac8b-dfcff7711b14")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "ITS" CACHE STRING "Trace prefix")
+
+target_include_directories(internal-trusted-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "internal-trusted-storage")
+
+#-------------------------------------------------------------------------------
+# Add components - this deployment uses an infrastructure that provides
+# ram backed storage for SFS.
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "internal-trusted-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/opteesp
+)
+
+include(../../env/commonsp/its_sp.cmake REQUIRED)
+include(../../internal-trusted-storage.cmake REQUIRED)
+include(../../infra/sfs-ram.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#
+#-------------------------------------------------------------------------------
+target_compile_definitions(internal-trusted-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(internal-trusted-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS internal-trusted-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "internal-trusted-storage"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_internal-trusted-storage.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/internal-trusted-storage/opteesp/default_internal-trusted-storage.dts.in b/deployments/internal-trusted-storage/config/default-opteesp/default_internal-trusted-storage.dts.in
index 3ce8dd6da..77d08051c 100644
--- a/deployments/internal-trusted-storage/opteesp/default_internal-trusted-storage.dts.in
+++ b/deployments/internal-trusted-storage/config/default-opteesp/default_internal-trusted-storage.dts.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,5 +15,7 @@
exception-level = <1>; /* S-EL0 */
execution-state = <0>; /* AArch64 */
xlat-granule = <0>; /* 4KiB */
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
};
diff --git a/deployments/internal-trusted-storage/config/default-opteesp/optee_sp_user_defines.h b/deployments/internal-trusted-storage/config/default-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..bbcc12be7
--- /dev/null
+++ b/deployments/internal-trusted-storage/config/default-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/internal-trusted-storage/config/default-sp/CMakeLists.txt b/deployments/internal-trusted-storage/config/default-sp/CMakeLists.txt
new file mode 100644
index 000000000..90c0f701d
--- /dev/null
+++ b/deployments/internal-trusted-storage/config/default-sp/CMakeLists.txt
@@ -0,0 +1,92 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the internal-trusted-storage deployment for
+# generic sp environment.
+#
+# Builds the secure storage service provider for running in an SEL0 secure
+# partition hosted by any SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(internal-trusted-storage)
+target_include_directories(internal-trusted-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_NAME "internal-trusted-storage")
+set(SP_BIN_UUID_CANON "dc1eef48-b17a-4ccf-ac8b-dfcff7711b14")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(TRACE_PREFIX "ITS" CACHE STRING "Trace prefix")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "internal-trusted-storage")
+
+#-------------------------------------------------------------------------------
+# Add components - this deployment uses an infrastructure that provides
+# ram backed storage for SFS.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "internal-trusted-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+include(../../env/commonsp/its_sp.cmake REQUIRED)
+include(../../internal-trusted-storage.cmake REQUIRED)
+include(../../infra/sfs-ram.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#
+#-------------------------------------------------------------------------------
+target_compile_definitions(internal-trusted-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(internal-trusted-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET internal-trusted-storage NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET internal-trusted-storage NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS internal-trusted-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake REQUIRED)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/internal-trusted-storage/config/default-sp/default_internal-trusted-storage.dts.in b/deployments/internal-trusted-storage/config/default-sp/default_internal-trusted-storage.dts.in
new file mode 100644
index 000000000..bfe55b651
--- /dev/null
+++ b/deployments/internal-trusted-storage/config/default-sp/default_internal-trusted-storage.dts.in
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "ITS";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ #include "@EXPORT_DTS_MEM_REGIONS@"
+ };
+};
diff --git a/deployments/internal-trusted-storage/config/shared-flash-opteesp/CMakeLists.txt b/deployments/internal-trusted-storage/config/shared-flash-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..7a0c20966
--- /dev/null
+++ b/deployments/internal-trusted-storage/config/shared-flash-opteesp/CMakeLists.txt
@@ -0,0 +1,81 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the internal-trusted-storage deployment for opteesp
+#
+# Builds the secure storage service provider for running in an SEL0 secure
+# partition hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(internal-trusted-storage)
+target_include_directories(internal-trusted-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "dc1eef48-b17a-4ccf-ac8b-dfcff7711b14")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "ITS" CACHE STRING "Trace prefix")
+
+target_include_directories(internal-trusted-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Add components - this deployment uses an infrastructure that provides
+# access to a storage partition in a shared secure flash device.
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "internal-trusted-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/opteesp
+)
+
+include(../../env/commonsp/its_sp.cmake REQUIRED)
+include(../../internal-trusted-storage.cmake REQUIRED)
+include(../../infra/sfs-shared-flash.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#
+#-------------------------------------------------------------------------------
+target_compile_definitions(internal-trusted-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(internal-trusted-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS internal-trusted-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "internal-trusted-storage"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_internal-trusted-storage.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/internal-trusted-storage/config/shared-flash-opteesp/default_internal-trusted-storage.dts.in b/deployments/internal-trusted-storage/config/shared-flash-opteesp/default_internal-trusted-storage.dts.in
new file mode 100644
index 000000000..77d08051c
--- /dev/null
+++ b/deployments/internal-trusted-storage/config/shared-flash-opteesp/default_internal-trusted-storage.dts.in
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "ITS";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/internal-trusted-storage/config/shared-flash-opteesp/optee_sp_user_defines.h b/deployments/internal-trusted-storage/config/shared-flash-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..bbcc12be7
--- /dev/null
+++ b/deployments/internal-trusted-storage/config/shared-flash-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/internal-trusted-storage/env/commonsp/its_sp.c b/deployments/internal-trusted-storage/env/commonsp/its_sp.c
new file mode 100644
index 000000000..03c98ff89
--- /dev/null
+++ b/deployments/internal-trusted-storage/env/commonsp/its_sp.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h"
+#include "components/service/secure_storage/factory/storage_factory.h"
+#include "components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h"
+#include "components/service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_messaging.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+
+static uint8_t tx_buffer[4096] __aligned(4096);
+static uint8_t rx_buffer[4096] __aligned(4096);
+
+void sp_main(union ffa_boot_info *boot_info)
+{
+ sp_result result = SP_RESULT_INTERNAL_ERROR;
+ struct rpc_service_interface *secure_storage_iface = NULL;
+ struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
+ struct sp_msg req_msg = { 0 };
+ struct sp_msg resp_msg = { 0 };
+ struct secure_storage_provider secure_storage_provider = { 0 };
+ struct storage_backend *storage_backend = NULL;
+ uint16_t own_id = 0;
+ const struct rpc_uuid service_uuid = { .uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID };
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Boot */
+ (void)boot_info;
+
+ result = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", result);
+ goto fatal_error;
+ }
+
+ result = sp_discovery_own_id_get(&own_id);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", result);
+ goto fatal_error;
+ }
+
+ storage_backend = storage_factory_create(storage_factory_security_class_INTERNAL_TRUSTED);
+ if (!storage_backend) {
+ EMSG("Failed to create storage backend");
+ goto fatal_error;
+ }
+
+ secure_storage_iface = secure_storage_provider_init(&secure_storage_provider,
+ storage_backend, &service_uuid);
+ if (!secure_storage_iface) {
+ EMSG("Failed to init secure storage provider");
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_init(&rpc_endpoint, 1, 16);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to initialize RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, secure_storage_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /* End of boot phase */
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ ts_rpc_endpoint_sp_receive(&rpc_endpoint, &req_msg, &resp_msg);
+
+ result = sp_msg_send_direct_resp(&resp_msg, &req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("ITS SP error");
+ while (1) {}
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
diff --git a/deployments/internal-trusted-storage/env/commonsp/its_sp.cmake b/deployments/internal-trusted-storage/env/commonsp/its_sp.cmake
new file mode 100644
index 000000000..a24dac786
--- /dev/null
+++ b/deployments/internal-trusted-storage/env/commonsp/its_sp.cmake
@@ -0,0 +1,31 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the internal-trusted-storage service provider
+# within a secure partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for internal-trusted-storage sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "internal-trusted-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/common/endpoint"
+ "components/rpc/common/interface"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/endpoint/sp"
+)
+
+target_sources(internal-trusted-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/its_sp.c
+)
diff --git a/deployments/internal-trusted-storage/env/commonsp/its_sp.h b/deployments/internal-trusted-storage/env/commonsp/its_sp.h
new file mode 100644
index 000000000..20562a492
--- /dev/null
+++ b/deployments/internal-trusted-storage/env/commonsp/its_sp.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#ifndef ITS_SP_H
+#define ITS_SP_H
+
+#endif /* ITS_SP_H */
diff --git a/deployments/internal-trusted-storage/infra/sfs-ram.cmake b/deployments/internal-trusted-storage/infra/sfs-ram.cmake
new file mode 100644
index 000000000..03af4f1e9
--- /dev/null
+++ b/deployments/internal-trusted-storage/infra/sfs-ram.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Lists components that provide an infrastructure layer for the
+# internal-trusted-storage service provider that uses the SFS component
+# backed by ram storage. Not intended to production deployments.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "internal-trusted-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/service/secure_storage/backend/secure_flash_store"
+ "components/service/secure_storage/backend/secure_flash_store/flash_fs"
+ "components/service/secure_storage/backend/secure_flash_store/flash"
+ "components/service/secure_storage/backend/secure_flash_store/flash/ram"
+ "components/service/secure_storage/factory/common/sfs"
+)
diff --git a/deployments/internal-trusted-storage/infra/sfs-shared-flash.cmake b/deployments/internal-trusted-storage/infra/sfs-shared-flash.cmake
new file mode 100644
index 000000000..f518d7334
--- /dev/null
+++ b/deployments/internal-trusted-storage/infra/sfs-shared-flash.cmake
@@ -0,0 +1,34 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Lists components that provide an infrastructure layer for the
+# internal-trusted-storage service provider that uses the SFS component
+# backed by a storage partition provided by the block storage service.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "internal-trusted-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/uuid"
+ "components/rpc/common/caller"
+ "components/rpc/ts_rpc/caller/sp"
+ "components/service/common/client"
+ "components/service/locator"
+ "components/service/locator/interface"
+ "components/service/locator/sp"
+ "components/service/locator/sp/ffa"
+ "components/service/secure_storage/backend/secure_flash_store"
+ "components/service/secure_storage/backend/secure_flash_store/flash_fs"
+ "components/service/secure_storage/backend/secure_flash_store/flash"
+ "components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter"
+ "components/service/secure_storage/factory/sp/sfs_shared_block_store"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/client"
+ "components/service/block_storage/factory/client"
+)
diff --git a/deployments/internal-trusted-storage/internal-trusted-storage.cmake b/deployments/internal-trusted-storage/internal-trusted-storage.cmake
new file mode 100644
index 000000000..3da2a0b20
--- /dev/null
+++ b/deployments/internal-trusted-storage/internal-trusted-storage.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "internal-trusted-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ components/common/tlv
+ components/service/common/include
+ components/service/common/provider
+ components/service/secure_storage/include
+ components/service/secure_storage/frontend/secure_storage_provider
+ protocols/rpc/common/packed-c
+ protocols/service/secure_storage/packed-c
+)
+
+target_include_directories(internal-trusted-storage PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
diff --git a/deployments/internal-trusted-storage/opteesp/.gitignore b/deployments/internal-trusted-storage/opteesp/.gitignore
deleted file mode 100644
index 378eac25d..000000000
--- a/deployments/internal-trusted-storage/opteesp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-build
diff --git a/deployments/internal-trusted-storage/opteesp/CMakeLists.txt b/deployments/internal-trusted-storage/opteesp/CMakeLists.txt
deleted file mode 100644
index 25d910b9b..000000000
--- a/deployments/internal-trusted-storage/opteesp/CMakeLists.txt
+++ /dev/null
@@ -1,102 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
-include(../../deployment.cmake REQUIRED)
-
-#-------------------------------------------------------------------------------
-# The CMakeLists.txt for building the internal-trusted-storage deployment for opteesp
-#
-# Builds the secure storage service provider for running in an SEL0 secure
-# partition hosted by OPTEE in the role of SPM.
-#-------------------------------------------------------------------------------
-include(${TS_ROOT}/environments/opteesp/env.cmake)
-project(trusted-services LANGUAGES C ASM)
-add_executable(internal-trusted-storage)
-target_include_directories(internal-trusted-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
-set(SP_UUID "dc1eef48-b17a-4ccf-ac8b-dfcff7711b14")
-set(TRACE_PREFIX "ITS" CACHE STRING "Trace prefix")
-
-
-# Include SP DEV KIT interface
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit COMPONENTS SP_HEADER interface)
-
-sp_dev_kit_configure_linking(TARGET internal-trusted-storage DEFINES ARM64=1)
-target_link_libraries(internal-trusted-storage ${SP_DEV_KIT_LIBRARIES})
-
-add_components(TARGET "internal-trusted-storage"
- BASE_DIR ${TS_ROOT}
- COMPONENTS
- components/common/trace
- components/common/utils
- components/messaging/ffa/libsp
- components/rpc/ffarpc/endpoint
- components/rpc/common/interface
- components/service/common/include
- components/service/common/provider
- components/service/secure_storage/include
- components/service/secure_storage/frontend/secure_storage_provider
- components/service/secure_storage/backend/secure_flash_store
- components/service/secure_storage/backend/secure_flash_store/flash_fs
- components/service/secure_storage/backend/secure_flash_store/flash
- components/service/secure_storage/factory/common/sfs
- protocols/rpc/common/packed-c
- protocols/service/secure_storage/packed-c
- environments/opteesp
-)
-
-target_sources(internal-trusted-storage PRIVATE
- sp.c
-)
-
-target_compile_definitions(internal-trusted-storage PRIVATE
- ARM64=1
-)
-
-target_include_directories(internal-trusted-storage PRIVATE
- ${TS_ROOT}
- ${TS_ROOT}/components
- ${TS_ROOT}/deployments/internal-trusted-storage/opteesp
-)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_compile_options(internal-trusted-storage PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
- -std=c99
- )
-
- # Options for GCC that control linking
- target_link_options(internal-trusted-storage PRIVATE
- -zmax-page-size=4096
- )
- # Options directly for LD, these are not understood by GCC
- target_link_options(internal-trusted-storage PRIVATE
- -Wl,--as-needed
- -Wl,--sort-section=alignment
- # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
- )
-endif()
-
-compiler_generate_stripped_elf(TARGET internal-trusted-storage NAME "${SP_UUID}.stripped.elf" RES STRIPPED_ELF)
-
-######################################## install
-if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
-endif()
-install(TARGETS internal-trusted-storage
- PUBLIC_HEADER DESTINATION ${TS_ENV}/include
- RUNTIME DESTINATION ${TS_ENV}/bin
- )
-install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
-
-set(EXPORT_SP_NAME "internal-trusted-storage")
-set(EXPORT_SP_UUID ${SP_UUID})
-include(${TS_ROOT}/environments/opteesp/ExportSp.cmake)
diff --git a/deployments/internal-trusted-storage/opteesp/sp.c b/deployments/internal-trusted-storage/opteesp/sp.c
deleted file mode 100644
index a46990529..000000000
--- a/deployments/internal-trusted-storage/opteesp/sp.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "sp.h"
-#include <ffa_api.h>
-#include <components/rpc/common/endpoint/rpc_interface.h>
-#include <components/rpc/ffarpc/endpoint/ffarpc_call_ep.h>
-#include <components/service/secure_storage/factory/storage_factory.h>
-#include <components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h>
-#include <sp_api.h>
-#include <sp_messaging.h>
-#include <sp_rxtx.h>
-#include <trace.h>
-
-uint16_t own_id = 0;
-static uint8_t tx_buffer[4096] __aligned(4096);
-static uint8_t rx_buffer[4096] __aligned(4096);
-
-void sp_main(struct ffa_init_info *init_info)
-{
- ffa_result ffa_res;
- sp_result sp_res;
- struct rpc_interface *secure_storage_iface;
- struct ffa_call_ep ffa_call_ep;
- struct sp_msg req_msg = { 0 };
- struct sp_msg resp_msg = { 0 };
- struct secure_storage_provider secure_storage_provider;
- struct storage_backend *storage_backend;
-
- /* Boot */
- (void) init_info;
-
- ffa_res = ffa_id_get(&own_id);
- if (ffa_res != FFA_OK) {
- EMSG("id get error: %d", ffa_res);
- }
-
- sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
- if (sp_res != SP_RESULT_OK) {
- EMSG("rxtx map error: %d", sp_res);
- }
-
- storage_backend = storage_factory_create(storage_factory_security_class_INTERNAL_TRUSTED);
- secure_storage_iface = secure_storage_provider_init(&secure_storage_provider, storage_backend);
- ffa_call_ep_init(&ffa_call_ep, secure_storage_iface);
-
- /* End of boot phase */
- sp_msg_wait(&req_msg);
-
- while (1) {
- ffa_call_ep_receive(&ffa_call_ep, &req_msg, &resp_msg);
-
- resp_msg.source_id = req_msg.destination_id;
- resp_msg.destination_id = req_msg.source_id;
-
- sp_msg_send_direct_resp(&resp_msg, &req_msg);
- }
-}
-
-void sp_interrupt_handler(uint32_t interrupt_id)
-{
- (void)interrupt_id;
-}
diff --git a/deployments/internal-trusted-storage/opteesp/sp.h b/deployments/internal-trusted-storage/opteesp/sp.h
deleted file mode 100644
index 5aa76c3c4..000000000
--- a/deployments/internal-trusted-storage/opteesp/sp.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_H
-#define SP_H
-
-/* UUID for the Internal Trusted Store */
-#define OPTEE_SP_UUID \
- { 0xdc1eef48, 0xb17a, 0x4ccf, \
- { 0xac, 0x8b, 0xdf, 0xcf, 0xf7, 0x71, 0x1b, 0x14 } }
-
-#define SP_UUID_BYTES \
- { 0xdc, 0x1e, 0xef, 0x48, 0xb1, 0x7a, 0x4c, 0xcf, \
- 0xac, 0x8b, 0xdf, 0xcf, 0xf7, 0x71, 0x1b, 0x14, }
-
-#endif /* SP_H */
diff --git a/deployments/libsp/linux-pc/CMakeLists.txt b/deployments/libsp/linux-pc/CMakeLists.txt
index 2b50c976e..dba25155f 100644
--- a/deployments/libsp/linux-pc/CMakeLists.txt
+++ b/deployments/libsp/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
project(libsp-unit-tests LANGUAGES CXX C)
diff --git a/deployments/libsp/opteesp/CMakeLists.txt b/deployments/libsp/opteesp/CMakeLists.txt
index 6f3907f26..a690c0c75 100644
--- a/deployments/libsp/opteesp/CMakeLists.txt
+++ b/deployments/libsp/opteesp/CMakeLists.txt
@@ -1,56 +1,69 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
# The CMakeLists.txt for building the libsp deployment for opteesp
#
-# Used for building the libsp library that provides FFA related functons
+# Used for building the libsp library that provides FFA related functions
# for applications deployed in a secure partition.
#-------------------------------------------------------------------------------
include(${TS_ROOT}/environments/opteesp/env.cmake)
-file(READ "${CMAKE_CURRENT_LIST_DIR}/version.txt" LIBSP_VERSION)
+version_semver_read(FILE "${CMAKE_CURRENT_LIST_DIR}/version.txt"
+ MAJOR _major MINOR _minor PATCH _patch)
+set(LIBSP_VERSION "${_major}.${_minor}.${_patch}")
project(trusted-services
VERSION
${LIBSP_VERSION}
LANGUAGES
C ASM
)
+unset(_major)
+unset(_minor)
+unset(_patch)
add_library(sp STATIC)
-# Include SP DEV KIT interface
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit COMPONENTS interface)
-
-target_link_libraries(sp PUBLIC ${SP_DEV_KIT_LIBRARIES})
-
-
-add_components(TARGET "sp"
+add_components(TARGET sp
BASE_DIR ${TS_ROOT}
COMPONENTS
components/messaging/ffa/libsp
components/common/utils
- environments/opteesp
)
-target_compile_definitions("sp" PRIVATE
+# Include newlib into the build, but do no add SP executable specific files to libsp.
+# Use a dummy target which will never be built.
+function(get_newlib_compile_flags)
+ # Environment specific files require this variable to be set.
+ # Set it to a dummy value as we are not going to build these anyways.
+ # The namespace of the function will ensure globas setting is not affected.
+ set(SP_FFA_UUID_CANON "00000000-0000-0000-0000-000000000000")
+ set(SP_HEAP_SIZE 4096)
+ add_library(dummy EXCLUDE_FROM_ALL)
+ add_components(TARGET dummy
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/opteesp
+ )
+endfunction()
+
+get_newlib_compile_flags()
+
+# Get libc specific settings from newlib.
+target_link_libraries(sp PUBLIC stdlib::c)
+
+target_compile_definitions(sp PRIVATE
ARM64=1
)
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_compile_options("sp" PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
+ target_compile_options(sp PRIVATE
-std=c99
)
endif()
@@ -73,16 +86,13 @@ install(
libsp
)
-#These would install the spdevkit content.
-#install(FILES $<TARGET_PROPERTY:sp_devkit_ifc,INTERFACE_LINK_LIBRARIES> DESTINATION lib)
-#install(FILES $<TARGET_PROPERTY:sp_devkit_ifc,INTERFACE_INCLUDE_DIRECTORIES>/ DESTINATION include)
### Create a config file package.
set(ConfigPackageLocation ${TS_ENV}/lib/cmake/libsp)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/LibspConfigVersion.cmake"
- VERSION "1.0.0"
+ VERSION "${LIBSP_VERSION}"
COMPATIBILITY SameMajorVersion
)
@@ -124,7 +134,6 @@ install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/LibspConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/LibspConfigVersion.cmake"
- "${TS_ROOT}/external/Spdevkit/FindSpdevkit.cmake"
DESTINATION
${ConfigPackageLocation}
COMPONENT
diff --git a/deployments/libsp/opteesp/LibspConfig.cmake.in b/deployments/libsp/opteesp/LibspConfig.cmake.in
index cd8d0d6a4..559b35d03 100644
--- a/deployments/libsp/opteesp/LibspConfig.cmake.in
+++ b/deployments/libsp/opteesp/LibspConfig.cmake.in
@@ -1,16 +1,9 @@
#
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@PACKAGE_INIT@
-# Any user of the lib will depend on spdevkit. Use our find module to get access to it.
-find_package(Spdevkit
- COMPONENTS LIBUTIL
- PATHS ${CMAKE_CURRENT_LIST_DIR}
- NO_DEFAULT_PATH
- REQUIRED)
-
include("${CMAKE_CURRENT_LIST_DIR}/LibspTargets.cmake")
diff --git a/deployments/libsp/opteesp/version.txt b/deployments/libsp/opteesp/version.txt
index afaf360d3..359a5b952 100644
--- a/deployments/libsp/opteesp/version.txt
+++ b/deployments/libsp/opteesp/version.txt
@@ -1 +1 @@
-1.0.0 \ No newline at end of file
+2.0.0 \ No newline at end of file
diff --git a/deployments/libts/arm-linux/CMakeLists.txt b/deployments/libts/arm-linux/CMakeLists.txt
index 3bb2e4747..1c190a88c 100644
--- a/deployments/libts/arm-linux/CMakeLists.txt
+++ b/deployments/libts/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
@@ -19,6 +19,10 @@ project(trusted-services LANGUAGES CXX C)
add_library(ts SHARED)
target_include_directories(ts PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+# Setting the MM communication buffer parameters
+set(MM_COMM_BUFFER_ADDRESS "0x881000000" CACHE STRING "Address of MM communicte buffer")
+set(MM_COMM_BUFFER_SIZE "8*4*1024" CACHE STRING "Size of the MM communicate buffer in bytes")
+
#-------------------------------------------------------------------------------
# Components that are specific to deployment in the arm-linux environment.
#
@@ -28,7 +32,7 @@ add_components(
BASE_DIR ${TS_ROOT}
COMPONENTS
"components/common/utils"
- "components/rpc/ffarpc/caller/linux"
+ "components/rpc/ts_rpc/caller/linux"
"components/rpc/mm_communicate/caller/linux"
"components/service/locator/linux"
"components/service/locator/linux/ffa"
@@ -47,5 +51,4 @@ include(../libts.cmake REQUIRED)
# Define library options and dependencies.
#
#-------------------------------------------------------------------------------
-env_set_link_options(TGT ts)
target_link_libraries(ts PRIVATE gcc)
diff --git a/deployments/libts/libts-import.cmake b/deployments/libts/libts-import.cmake
index 792ba86c7..fd016ca7e 100644
--- a/deployments/libts/libts-import.cmake
+++ b/deployments/libts/libts-import.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -11,48 +11,58 @@
# CMake build file allows libts to be built and installed into the binary
# directory of the dependent.
#-------------------------------------------------------------------------------
+option(CFG_FORCE_PREBUILT_LIBTS Off)
+# Try to find a pre-build package.
+version_semver_read(FILE "${CMAKE_CURRENT_LIST_DIR}/version.txt" MAJOR _major MINOR _minor PATCH _patch)
+set(_verstring "${_major}.${_minor}.${_patch}")
-# Determine the number of processes to run while running parallel builds.
-# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
-if(NOT DEFINED PROCESSOR_COUNT)
- include(ProcessorCount)
- ProcessorCount(PROCESSOR_COUNT)
- set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
-endif()
-
-set(LIBTS_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/libts_install" CACHE PATH "libts installation directory")
-set(LIBTS_PACKAGE_PATH "${LIBTS_INSTALL_PATH}/lib/cmake" CACHE PATH "libts CMake package directory")
-set(LIBTS_SOURCE_DIR "${TS_ROOT}/deployments/libts/${TS_ENV}" CACHE PATH "libts source directory")
-set(LIBTS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/libts-build" CACHE PATH "libts binary directory")
+find_package(libts "${_verstring}" QUIET PATHS ${CMAKE_CURRENT_BINARY_DIR}/libts_install/${TS_ENV}/lib/cmake/libts)
+if(NOT libts_FOUND)
+ if (CFG_FORCE_PREBUILT_LIBTS)
+ string(CONCAT _msg "find_package() failed to find the \"libts\" package. Please pass -Dlibts_ROOT=<path> or"
+ " -DCMAKE_FIND_ROOT_PATH=<path> cmake variable, where <path> is the INSTALL_PREFIX used"
+ " when building libts. libts_ROOT can be set in the environment too."
+ "If you wish to debug the search process pass -DCMAKE_FIND_DEBUG_MODE=ON to cmake.")
+ message(FATAL_ERROR ${_msg})
+ endif()
+ # If not successful, build libts as a sub-project.
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
+ ${CMAKE_COMMAND}
+ -S ${TS_ROOT}/deployments/libts/${TS_ENV}
+ -B ${CMAKE_CURRENT_BINARY_DIR}/libts
+ RESULT_VARIABLE
+ _exec_error
+ )
+ if (NOT _exec_error EQUAL 0)
+ message(FATAL_ERROR "Configuring libts failed. ${_exec_error}")
+ endif()
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
+ ${CMAKE_COMMAND}
+ --build ${CMAKE_CURRENT_BINARY_DIR}/libts
+ --parallel ${PROCESSOR_COUNT}
+ RESULT_VARIABLE
+ _exec_error
+ )
+ if (NOT _exec_error EQUAL 0)
+ message(FATAL_ERROR "Installing libts failed. ${_exec_error}")
+ endif()
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
+ ${CMAKE_COMMAND}
+ --install ${CMAKE_CURRENT_BINARY_DIR}/libts
+ --prefix ${CMAKE_CURRENT_BINARY_DIR}/libts_install
+ RESULT_VARIABLE
+ _exec_error
+ )
+ if (NOT _exec_error EQUAL 0)
+ message(FATAL_ERROR "Installing libts failed. ${_exec_error}")
+ endif()
-file(MAKE_DIRECTORY ${LIBTS_BINARY_DIR})
+ install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/libts/cmake_install.cmake)
-#Configure the library
-execute_process(COMMAND
- ${CMAKE_COMMAND}
- -DCMAKE_INSTALL_PREFIX=${LIBTS_INSTALL_PATH}
- -GUnix\ Makefiles
- ${LIBTS_SOURCE_DIR}
- WORKING_DIRECTORY
- ${LIBTS_BINARY_DIR}
-)
-
-if (_exec_error)
- message(FATAL_ERROR "Configuration step of libts failed with ${_exec_error}.")
+ find_package(libts "${_verstring}" QUIET REQUIRED PATHS ${CMAKE_CURRENT_BINARY_DIR}/libts_install/${TS_ENV}/lib/cmake/libts)
+else()
+ message(STATUS "Using prebuilt libts from ${libts_DIR}")
endif()
-
-#Build the library
-execute_process(COMMAND
- ${CMAKE_COMMAND} --build ${LIBTS_BINARY_DIR} --parallel ${PROCESSOR_COUNT} --target install
- RESULT_VARIABLE _exec_error
-)
-
-if (_exec_error)
- message(FATAL_ERROR "Build step of libts failed with ${_exec_error}.")
-endif()
-
-# Import the built library
-include(${LIBTS_INSTALL_PATH}/${TS_ENV}/lib/cmake/libts_targets.cmake)
-add_library(libts SHARED IMPORTED)
-set_property(TARGET libts PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${LIBTS_INSTALL_PATH}/${TS_ENV}/include")
-set_property(TARGET libts PROPERTY IMPORTED_LOCATION "${LIBTS_INSTALL_PATH}/${TS_ENV}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}ts${CMAKE_SHARED_LIBRARY_SUFFIX}")
diff --git a/deployments/libts/libts.cmake b/deployments/libts/libts.cmake
index 6463ca174..0f1a0228a 100644
--- a/deployments/libts/libts.cmake
+++ b/deployments/libts/libts.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -22,8 +22,10 @@ unset(_major)
unset(_minor)
unset(_patch)
+add_library(libts::ts ALIAS ts)
+
#-------------------------------------------------------------------------------
-# Components that are common accross all deployments
+# Components that are common across all deployments
#
#-------------------------------------------------------------------------------
add_components(
@@ -44,29 +46,22 @@ add_components(
# Enable exporting interface symbols for library public interface
target_compile_definitions(ts PRIVATE
EXPORT_PUBLIC_INTERFACE_RPC_CALLER
+ EXPORT_PUBLIC_INTERFACE_RPC_SERVICE
EXPORT_PUBLIC_INTERFACE_SERVICE_LOCATOR
)
+# Do not export symbols from static libraries linked to this library
+target_link_options(ts PRIVATE -Wl,--exclude-libs,ALL)
+
#-------------------------------------------------------------------------------
# Export the library and the corresponding public interface header files
#
#-------------------------------------------------------------------------------
include(${TS_ROOT}/tools/cmake/common/ExportLibrary.cmake REQUIRED)
-# Select public header files to export
-get_property(_rpc_caller_public_header_files TARGET ts
- PROPERTY RPC_CALLER_PUBLIC_HEADER_FILES
-)
-
-get_property(_service_locator_public_header_files TARGET ts
- PROPERTY SERVICE_LOCATOR_PUBLIC_HEADER_FILES
-)
-
# Exports library information in preparation for install
export_library(
TARGET "ts"
LIB_NAME "libts"
- INTERFACE_FILES
- ${_rpc_caller_public_header_files}
- ${_service_locator_public_header_files}
+ PKG_CONFIG_FILE "${CMAKE_CURRENT_LIST_DIR}/libtsConfig.cmake.in"
)
diff --git a/deployments/libts/libtsConfig.cmake.in b/deployments/libts/libtsConfig.cmake.in
new file mode 100644
index 000000000..486013536
--- /dev/null
+++ b/deployments/libts/libtsConfig.cmake.in
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/libtsTargets.cmake")
+
diff --git a/deployments/libts/linux-pc/CMakeLists.txt b/deployments/libts/linux-pc/CMakeLists.txt
index fc98407c2..2660a78a2 100644
--- a/deployments/libts/linux-pc/CMakeLists.txt
+++ b/deployments/libts/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
@@ -22,6 +22,34 @@ add_library(ts SHARED)
target_include_directories(ts PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
#-------------------------------------------------------------------------------
+# External project source-level dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET "ts")
+
+#-------------------------------------------------------------------------------
+# Options and variables
+#-------------------------------------------------------------------------------
+target_compile_definitions(ts PRIVATE
+ -DUEFI_AUTH_VAR
+)
+
+#-------------------------------------------------------------------------------
+# Define public interfaces for library
+#
+#-------------------------------------------------------------------------------
+
+# Extend libts public interface for linux-pc to allow for alternative fwu
+# device configurations. This is intended for test.
+target_compile_definitions(ts PRIVATE
+ EXPORT_PUBLIC_INTERFACE_FWU_SERVICE_CONTEXT
+)
+
+# Enable RPMB authentication key write for host tests
+set(RPMB_WRITE_KEY TRUE CACHE BOOL "Enable RPMB Authentication Key Write")
+
+#-------------------------------------------------------------------------------
# Components that are specific to deployment in the linux-pc environment.
#
#-------------------------------------------------------------------------------
@@ -30,22 +58,27 @@ add_components(
BASE_DIR ${TS_ROOT}
COMPONENTS
"components/rpc/direct"
+ "components/rpc/common/endpoint"
"components/common/tlv"
+ "components/common/uuid"
"components/common/endian"
"components/common/utils"
+ "components/common/trace"
+ "components/common/crc32"
"components/config/ramstore"
"components/service/common/include"
"components/service/common/client"
"components/service/common/serializer/protobuf"
"components/service/common/provider"
- "components/service/discovery/provider"
- "components/service/discovery/provider/serializer/packed-c"
"components/service/locator/standalone"
"components/service/locator/standalone/services/crypto"
"components/service/locator/standalone/services/internal-trusted-storage"
"components/service/locator/standalone/services/protected-storage"
"components/service/locator/standalone/services/test-runner"
"components/service/locator/standalone/services/attestation"
+ "components/service/locator/standalone/services/block-storage"
+ "components/service/locator/standalone/services/fwu"
+ "components/service/locator/standalone/services/rpmb"
"components/service/locator/standalone/services/smm-variable"
"components/service/attestation/include"
"components/service/attestation/claims"
@@ -60,6 +93,19 @@ add_components(
"components/service/attestation/key_mngr/local"
"components/service/attestation/provider"
"components/service/attestation/provider/serializer/packed-c"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/ram"
+ "components/service/block_storage/block_store/device/rpmb"
+ "components/service/block_storage/block_store/partitioned"
+ "components/service/block_storage/block_store/client"
+ "components/service/block_storage/provider"
+ "components/service/block_storage/provider/serializer/packed-c"
+ "components/service/block_storage/config/gpt"
+ "components/service/block_storage/config/ref"
+ "components/service/block_storage/factory/ref_ram_gpt"
+ "components/service/block_storage/factory/client"
+ "components/service/block_storage/factory/rpmb"
"components/service/crypto/provider"
"components/service/crypto/provider/serializer/protobuf"
"components/service/crypto/provider/serializer/packed-c"
@@ -71,21 +117,41 @@ add_components(
"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
"components/service/crypto/provider/extension/mac"
"components/service/crypto/provider/extension/mac/serializer/packed-c"
+ "components/service/crypto/provider/extension/aead"
+ "components/service/crypto/provider/extension/aead/serializer/packed-c"
"components/service/crypto/factory/full"
"components/service/crypto/backend/mbedcrypto"
"components/service/crypto/backend/mbedcrypto/trng_adapter/linux"
+ "components/service/rpmb/backend"
+ "components/service/rpmb/backend/emulated"
+ "components/service/rpmb/client"
+ "components/service/rpmb/frontend"
+ "components/service/rpmb/frontend/platform/default"
+ "components/service/rpmb/provider"
"components/service/secure_storage/include"
"components/service/secure_storage/frontend/psa/its"
"components/service/secure_storage/frontend/secure_storage_provider"
"components/service/secure_storage/backend/secure_storage_client"
"components/service/secure_storage/backend/mock_store"
"components/service/secure_storage/backend/null_store"
+ "components/service/secure_storage/backend/secure_flash_store"
+ "components/service/secure_storage/backend/secure_flash_store/flash_fs"
+ "components/service/secure_storage/backend/secure_flash_store/flash"
+ "components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter"
"components/service/test_runner/provider"
"components/service/test_runner/provider/serializer/packed-c"
"components/service/test_runner/provider/backend/mock"
"components/service/test_runner/provider/backend/simple_c"
- "components/service/smm_variable/backend"
- "components/service/smm_variable/provider"
+ "components/service/uefi/smm_variable/backend"
+ "components/service/uefi/smm_variable/backend/direct"
+ "components/service/uefi/smm_variable/provider"
+ "components/media/disk"
+ "components/media/disk/disk_images"
+ "components/media/disk/formatter"
+ "components/media/volume"
+ "components/media/volume/index"
+ "components/media/volume/base_io_dev"
+ "components/media/volume/block_volume"
"protocols/rpc/common/packed-c"
"protocols/service/crypto/packed-c"
"protocols/service/crypto/protobuf"
@@ -93,6 +159,14 @@ add_components(
)
#-------------------------------------------------------------------------------
+# Configure added components
+#
+#-------------------------------------------------------------------------------
+# Force trace level to TRACE_LEVEL_NONE to disable trace messages. This is
+# needed till proper trace enablement for the linux-pc environment is done.
+target_compile_definitions(ts PUBLIC TRACE_LEVEL=0)
+
+#-------------------------------------------------------------------------------
# Extend with components that are common across all deployments of
# libts
#
@@ -109,9 +183,17 @@ include(${TS_ROOT}/external/nanopb/nanopb.cmake)
target_link_libraries(ts PRIVATE nanopb::protobuf-nanopb-static)
protobuf_generate_all(TGT "ts" NAMESPACE "protobuf" BASE_DIR "${TS_ROOT}/protocols")
-# Mbed TLS provides libmbedcrypto
+# MbedTLS
+set(MBEDTLS_USER_CONFIG_FILE "${TS_ROOT}/external/MbedTLS/config/libmbedx509.h"
+ CACHE STRING "Configuration file for Mbed TLS" FORCE)
include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(ts PRIVATE mbedcrypto)
+target_link_libraries(ts PRIVATE MbedTLS::mbedcrypto)
+target_link_libraries(ts PRIVATE MbedTLS::mbedx509)
+
+# Pass the location of the mbedtls config file to C preprocessor.
+target_compile_definitions(ts PRIVATE
+ MBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}"
+)
# Qcbor
include(${TS_ROOT}/external/qcbor/qcbor.cmake)
@@ -135,8 +217,10 @@ add_components(
COMPONENTS
"components/app/test-runner"
"components/common/tlv"
+ "components/rpc/common/caller"
+ "components/rpc/common/interface"
+ "components/rpc/common/endpoint"
"components/service/common/include"
- "components/service/discovery/client"
"components/service/secure_storage/include"
"components/service/secure_storage/test/service"
"components/service/secure_storage/frontend/psa/its"
@@ -170,4 +254,4 @@ target_link_libraries(libts-test PRIVATE nanopb::protobuf-nanopb-static)
protobuf_generate_all(TGT "libts-test" NAMESPACE "protobuf" BASE_DIR "${TS_ROOT}/protocols")
# Mbedcrypto
-target_link_libraries(libts-test PRIVATE mbedcrypto)
+target_link_libraries(libts-test PRIVATE MbedTLS::mbedcrypto)
diff --git a/deployments/libts/version.txt b/deployments/libts/version.txt
index afaf360d3..359a5b952 100644
--- a/deployments/libts/version.txt
+++ b/deployments/libts/version.txt
@@ -1 +1 @@
-1.0.0 \ No newline at end of file
+2.0.0 \ No newline at end of file
diff --git a/deployments/newlib/opteesp/CMakeLists.txt b/deployments/newlib/opteesp/CMakeLists.txt
new file mode 100644
index 000000000..5363d848e
--- /dev/null
+++ b/deployments/newlib/opteesp/CMakeLists.txt
@@ -0,0 +1,31 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.14)
+include(../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the newlib deployment for opteesp
+#
+# Can be used to build the newlib library, which can be used to build SPs.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+
+project(newlib C)
+
+# This is a dummy library not intended to be compiled ever.
+add_library(dummy EXCLUDE_FROM_ALL)
+set(TGT dummy)
+# Build newlib as an external component.
+include(${TS_ROOT}/external/newlib/newlib.cmake)
+
+######################################## install
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+
+# export the newlib install content from CMAKE_BINARY_DIR.
+install(DIRECTORY ${NEWLIB_INSTALL_DIR}/ DESTINATION ${TS_ENV}/newlib)
diff --git a/deployments/platform-inspect/arm-linux/CMakeLists.txt b/deployments/platform-inspect/arm-linux/CMakeLists.txt
index f4d02c03c..416bd65ed 100644
--- a/deployments/platform-inspect/arm-linux/CMakeLists.txt
+++ b/deployments/platform-inspect/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
@@ -33,13 +33,4 @@ include(../platform-inspect.cmake REQUIRED)
# Define library options and dependencies.
#
#-------------------------------------------------------------------------------
-env_set_link_options(TGT platform-inspect)
target_link_libraries(platform-inspect PRIVATE stdc++ gcc m)
-
-#-------------------------------------------------------------------------------
-# Linker option to enable repeated searches for undefined references.
-# Required to resolve dependencies between t_cose and qcbor libraries.
-#-------------------------------------------------------------------------------
-target_link_options(platform-inspect PRIVATE
- -Wl,--start-group
- )
diff --git a/deployments/platform-inspect/linux-pc/CMakeLists.txt b/deployments/platform-inspect/linux-pc/CMakeLists.txt
index 52a583479..2b0962a69 100644
--- a/deployments/platform-inspect/linux-pc/CMakeLists.txt
+++ b/deployments/platform-inspect/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
diff --git a/deployments/platform-inspect/platform-inspect.cmake b/deployments/platform-inspect/platform-inspect.cmake
index ef4ba4ba3..dc65184b2 100644
--- a/deployments/platform-inspect/platform-inspect.cmake
+++ b/deployments/platform-inspect/platform-inspect.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -12,14 +12,14 @@
#-------------------------------------------------------------------------------
# Use libts for locating and accessing trusted services. An appropriate version
-# of libts will be imported for the enviroment in which platform-inspect is
+# of libts will be imported for the environment in which platform-inspect is
# built.
#-------------------------------------------------------------------------------
include(${TS_ROOT}/deployments/libts/libts-import.cmake)
-target_link_libraries(platform-inspect PRIVATE libts)
+target_link_libraries(platform-inspect PRIVATE libts::ts)
#-------------------------------------------------------------------------------
-# Components that are common accross all deployments
+# Components that are common across all deployments
#
#-------------------------------------------------------------------------------
add_components(
@@ -43,22 +43,20 @@ add_components(
#
#-------------------------------------------------------------------------------
-# Configuration for mbedcrypto
-set(MBEDTLS_USER_CONFIG_FILE
- "${TS_ROOT}/components/service/crypto/client/cpp/config_mbedtls_user.h"
+# MbedTLS provides libmbedcrypto
+set(MBEDTLS_USER_CONFIG_FILE "${TS_ROOT}/external/MbedTLS/config/crypto_posix.h"
CACHE STRING "Configuration file for mbedcrypto")
-
-# Mbed TLS provides libmbedcrypto
-include(../../../external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(platform-inspect PRIVATE mbedcrypto)
+include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
+target_link_libraries(platform-inspect PRIVATE MbedTLS::mbedcrypto)
# Qcbor
include(${TS_ROOT}/external/qcbor/qcbor.cmake)
-target_link_libraries(platform-inspect PRIVATE qcbor)
# t_cose
include(${TS_ROOT}/external/t_cose/t_cose.cmake)
-target_link_libraries(platform-inspect PRIVATE t_cose)
+# Ensure correct order of libraries on the command line of LD. t_cose depends on qcbor thus
+# qcbor must come later.
+target_link_libraries(platform-inspect PRIVATE t_cose qcbor)
#-------------------------------------------------------------------------------
# Define install content.
diff --git a/deployments/protected-storage/config/default-opteesp/CMakeLists.txt b/deployments/protected-storage/config/default-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..27540c7a9
--- /dev/null
+++ b/deployments/protected-storage/config/default-opteesp/CMakeLists.txt
@@ -0,0 +1,87 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the protected-storage deployment for opteesp
+#
+# Builds the secure storage service provider for running in an SEL0 secure
+# partition hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(protected-storage)
+target_include_directories(protected-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "751bf801-3dde-4768-a514-0f10aeed1790")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "PS" CACHE STRING "Trace prefix")
+
+target_include_directories(protected-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "protected-storage")
+
+#-------------------------------------------------------------------------------
+# Add components - this deployment uses an infrastructure that provides
+# ram backed storage for SFS.
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "protected-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/opteesp
+)
+
+include(../../env/commonsp/ps_sp.cmake REQUIRED)
+include(../../protected-storage.cmake REQUIRED)
+include(../../infra/sfs-ram.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#
+#-------------------------------------------------------------------------------
+target_compile_definitions(protected-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(protected-storage PRIVATE
+ -std=c99
+ )
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS protected-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "protected-storage"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_protected-storage.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/protected-storage/opteesp/default_protected-storage.dts.in b/deployments/protected-storage/config/default-opteesp/default_protected-storage.dts.in
index 1047a4c94..b305fbbf7 100644
--- a/deployments/protected-storage/opteesp/default_protected-storage.dts.in
+++ b/deployments/protected-storage/config/default-opteesp/default_protected-storage.dts.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,5 +15,7 @@
exception-level = <1>; /* S-EL0 */
execution-state = <0>; /* AArch64 */
xlat-granule = <0>; /* 4KiB */
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
};
diff --git a/deployments/protected-storage/config/default-opteesp/optee_sp_user_defines.h b/deployments/protected-storage/config/default-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..bbcc12be7
--- /dev/null
+++ b/deployments/protected-storage/config/default-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/protected-storage/config/default-sp/CMakeLists.txt b/deployments/protected-storage/config/default-sp/CMakeLists.txt
new file mode 100644
index 000000000..3b05daa91
--- /dev/null
+++ b/deployments/protected-storage/config/default-sp/CMakeLists.txt
@@ -0,0 +1,92 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the protected-storage deployment for generic
+# sp environment.
+#
+# Builds the secure storage service provider for running in an SEL0 secure
+# partition hosted by any SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(protected-storage)
+target_include_directories(protected-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_NAME "protected-storage")
+set(SP_BIN_UUID_CANON "751bf801-3dde-4768-a514-0f10aeed1790")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(TRACE_PREFIX "PS" CACHE STRING "Trace prefix")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "protected-storage")
+
+#-------------------------------------------------------------------------------
+# Add components - this deployment uses an infrastructure that provides
+# ram backed storage for SFS.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "protected-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+include(../../env/commonsp/ps_sp.cmake REQUIRED)
+include(../../protected-storage.cmake REQUIRED)
+include(../../infra/sfs-ram.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#
+#-------------------------------------------------------------------------------
+target_compile_definitions(protected-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(protected-storage PRIVATE
+ -std=c99
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET protected-storage NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET protected-storage NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS protected-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake REQUIRED)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/protected-storage/config/default-sp/default_protected-storage.dts.in b/deployments/protected-storage/config/default-sp/default_protected-storage.dts.in
new file mode 100644
index 000000000..38c9b5849
--- /dev/null
+++ b/deployments/protected-storage/config/default-sp/default_protected-storage.dts.in
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "PS";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ #include "@EXPORT_DTS_MEM_REGIONS@"
+ };
+};
diff --git a/deployments/protected-storage/config/shared-flash-opteesp/CMakeLists.txt b/deployments/protected-storage/config/shared-flash-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..1a3480dce
--- /dev/null
+++ b/deployments/protected-storage/config/shared-flash-opteesp/CMakeLists.txt
@@ -0,0 +1,79 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the protected-storage deployment for opteesp
+#
+# Builds the secure storage service provider for running in an SEL0 secure
+# partition hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(protected-storage)
+target_include_directories(protected-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "751bf801-3dde-4768-a514-0f10aeed1790")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "PS" CACHE STRING "Trace prefix")
+
+target_include_directories(protected-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Add components - this deployment uses an infrastructure that provides
+# access to a storage partition in a shared secure flash device.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "protected-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/opteesp
+)
+
+include(../../env/commonsp/ps_sp.cmake REQUIRED)
+include(../../protected-storage.cmake REQUIRED)
+include(../../infra/sfs-shared-flash.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#
+#-------------------------------------------------------------------------------
+target_compile_definitions(protected-storage PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(protected-storage PRIVATE
+ -std=c99
+ )
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS protected-storage
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "protected-storage"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_protected-storage.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/protected-storage/config/shared-flash-opteesp/default_protected-storage.dts.in b/deployments/protected-storage/config/shared-flash-opteesp/default_protected-storage.dts.in
new file mode 100644
index 000000000..b305fbbf7
--- /dev/null
+++ b/deployments/protected-storage/config/shared-flash-opteesp/default_protected-storage.dts.in
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "PS";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/protected-storage/config/shared-flash-opteesp/optee_sp_user_defines.h b/deployments/protected-storage/config/shared-flash-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..bbcc12be7
--- /dev/null
+++ b/deployments/protected-storage/config/shared-flash-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_USER_DEFINES_H
+#define OPTEE_SP_USER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/protected-storage/env/commonsp/ps_sp.c b/deployments/protected-storage/env/commonsp/ps_sp.c
new file mode 100644
index 000000000..c77d9fdd8
--- /dev/null
+++ b/deployments/protected-storage/env/commonsp/ps_sp.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h"
+#include "components/service/secure_storage/factory/storage_factory.h"
+#include "components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h"
+#include "components/service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_messaging.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+
+static uint8_t tx_buffer[4096] __aligned(4096);
+static uint8_t rx_buffer[4096] __aligned(4096);
+
+void sp_main(union ffa_boot_info *boot_info)
+{
+ sp_result result = SP_RESULT_INTERNAL_ERROR;
+ struct rpc_service_interface *secure_storage_iface = NULL;
+ struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
+ struct sp_msg req_msg = { 0 };
+ struct sp_msg resp_msg = { 0 };
+ struct secure_storage_provider secure_storage_provider = { 0 };
+ struct storage_backend *storage_backend = NULL;
+ uint16_t own_id = 0;
+ const struct rpc_uuid service_uuid = { .uuid = TS_PSA_PROTECTED_STORAGE_UUID };
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Boot */
+ (void)boot_info;
+
+ result = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", result);
+ goto fatal_error;
+ }
+
+ result = sp_discovery_own_id_get(&own_id);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", result);
+ goto fatal_error;
+ }
+
+ storage_backend = storage_factory_create(storage_factory_security_class_PROTECTED);
+ if (!storage_backend) {
+ EMSG("Failed to create storage backend");
+ goto fatal_error;
+ }
+
+ secure_storage_iface = secure_storage_provider_init(&secure_storage_provider,
+ storage_backend, &service_uuid);
+ if (!secure_storage_iface) {
+ EMSG("Failed to init secure storage provider");
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_init(&rpc_endpoint, 1, 16);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to initialize RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, secure_storage_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /* End of boot phase */
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ ts_rpc_endpoint_sp_receive(&rpc_endpoint, &req_msg, &resp_msg);
+
+ result = sp_msg_send_direct_resp(&resp_msg, &req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("ITS SP error");
+ while (1) {}
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
diff --git a/deployments/protected-storage/env/commonsp/ps_sp.cmake b/deployments/protected-storage/env/commonsp/ps_sp.cmake
new file mode 100644
index 000000000..c613f2258
--- /dev/null
+++ b/deployments/protected-storage/env/commonsp/ps_sp.cmake
@@ -0,0 +1,31 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the protected-storage service provider
+# within a secure partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for protected-storage sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "protected-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/common/endpoint"
+ "components/rpc/common/interface"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/endpoint/sp"
+)
+
+target_sources(protected-storage PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/ps_sp.c
+)
diff --git a/deployments/protected-storage/env/commonsp/ps_sp.h b/deployments/protected-storage/env/commonsp/ps_sp.h
new file mode 100644
index 000000000..ebe7df33c
--- /dev/null
+++ b/deployments/protected-storage/env/commonsp/ps_sp.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PS_SP_H
+#define PS_SP_H
+
+#endif /* PS_SP_H */
diff --git a/deployments/protected-storage/infra/sfs-ram.cmake b/deployments/protected-storage/infra/sfs-ram.cmake
new file mode 100644
index 000000000..dc73cd494
--- /dev/null
+++ b/deployments/protected-storage/infra/sfs-ram.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Lists components that provide an infrastructure layer for the
+# protected-storage service provider that uses the SFS component
+# backed by ram storage. Not intended to production deployments.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "protected-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/service/secure_storage/backend/secure_flash_store"
+ "components/service/secure_storage/backend/secure_flash_store/flash_fs"
+ "components/service/secure_storage/backend/secure_flash_store/flash"
+ "components/service/secure_storage/backend/secure_flash_store/flash/ram"
+ "components/service/secure_storage/factory/common/sfs"
+)
diff --git a/deployments/protected-storage/infra/sfs-shared-flash.cmake b/deployments/protected-storage/infra/sfs-shared-flash.cmake
new file mode 100644
index 000000000..6642e0d00
--- /dev/null
+++ b/deployments/protected-storage/infra/sfs-shared-flash.cmake
@@ -0,0 +1,34 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Lists components that provide an infrastructure layer for the
+# protected-storage service provider that uses the SFS component
+# backed by a storage partition provided by the block storage service.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "protected-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/uuid"
+ "components/rpc/common/caller"
+ "components/rpc/ts_rpc/caller/sp"
+ "components/service/common/client"
+ "components/service/locator"
+ "components/service/locator/interface"
+ "components/service/locator/sp"
+ "components/service/locator/sp/ffa"
+ "components/service/secure_storage/backend/secure_flash_store"
+ "components/service/secure_storage/backend/secure_flash_store/flash_fs"
+ "components/service/secure_storage/backend/secure_flash_store/flash"
+ "components/service/secure_storage/backend/secure_flash_store/flash/block_store_adapter"
+ "components/service/secure_storage/factory/sp/sfs_shared_block_store"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/client"
+ "components/service/block_storage/factory/client"
+)
diff --git a/deployments/protected-storage/opteesp/CMakeLists.txt b/deployments/protected-storage/opteesp/CMakeLists.txt
deleted file mode 100644
index e7f154a6f..000000000
--- a/deployments/protected-storage/opteesp/CMakeLists.txt
+++ /dev/null
@@ -1,104 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
-include(../../deployment.cmake REQUIRED)
-
-#-------------------------------------------------------------------------------
-# The CMakeLists.txt for building the protected-storage deployment for opteesp
-#
-# Builds the secure storage service provider for running in an SEL0 secure
-# partition hosted by OPTEE in the role of SPM.
-#-------------------------------------------------------------------------------
-include(${TS_ROOT}/environments/opteesp/env.cmake)
-project(trusted-services LANGUAGES C ASM)
-add_executable(protected-storage)
-target_include_directories(protected-storage PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
-set(SP_UUID "751bf801-3dde-4768-a514-0f10aeed1790")
-set(TRACE_PREFIX "PS" CACHE STRING "Trace prefix")
-
-
-# Include SP DEV KIT interface
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit COMPONENTS SP_HEADER interface)
-
-sp_dev_kit_configure_linking(TARGET protected-storage DEFINES ARM64=1)
-target_link_libraries(protected-storage ${SP_DEV_KIT_LIBRARIES})
-
-add_components(TARGET "protected-storage"
- BASE_DIR ${TS_ROOT}
- COMPONENTS
- components/common/trace
- components/common/utils
- components/messaging/ffa/libsp
- components/rpc/ffarpc/endpoint
- components/rpc/common/interface
- components/rpc/ffarpc/caller/sp
- components/rpc/common/caller
- components/service/common/include
- components/service/common/client
- components/service/common/provider
- components/service/secure_storage/include
- components/service/secure_storage/frontend/secure_storage_provider
- components/service/secure_storage/backend/secure_storage_client
- components/service/secure_storage/backend/null_store
- components/service/secure_storage/factory/sp/optee_trusted_store
- protocols/rpc/common/packed-c
- protocols/service/secure_storage/packed-c
- environments/opteesp
-)
-
-target_sources(protected-storage PRIVATE
- sp.c
-)
-
-target_compile_definitions(protected-storage PRIVATE
- ARM64=1
-)
-
-target_include_directories(protected-storage PRIVATE
- ${TS_ROOT}
- ${TS_ROOT}/components
- ${TS_ROOT}/deployments/protected-storage/opteesp
-)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_compile_options(protected-storage PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
- -std=c99
- )
-
- # Options for GCC that control linking
- target_link_options(protected-storage PRIVATE
- -zmax-page-size=4096
- )
- # Options directly for LD, these are not understood by GCC
- target_link_options(protected-storage PRIVATE
- -Wl,--as-needed
- -Wl,--sort-section=alignment
- # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
- )
-endif()
-
-compiler_generate_stripped_elf(TARGET protected-storage NAME "${SP_UUID}.stripped.elf" RES STRIPPED_ELF)
-
-######################################## install
-if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
-endif()
-install(TARGETS protected-storage
- PUBLIC_HEADER DESTINATION ${TS_ENV}/include
- RUNTIME DESTINATION ${TS_ENV}/bin
- )
-install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
-
-set(EXPORT_SP_NAME "protected-storage")
-set(EXPORT_SP_UUID ${SP_UUID})
-include(${TS_ROOT}/environments/opteesp/ExportSp.cmake)
diff --git a/deployments/protected-storage/opteesp/optee_sp_user_defines.h b/deployments/protected-storage/opteesp/optee_sp_user_defines.h
deleted file mode 100644
index e773055c4..000000000
--- a/deployments/protected-storage/opteesp/optee_sp_user_defines.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_HEADER_DEFINES_H
-#define SP_HEADER_DEFINES_H
-
-/* To get UUID definition */
-#include "sp.h"
-
-#define OPTEE_SP_FLAGS 0
-
-/* Provisioned stack size */
-#define OPTEE_SP_STACK_SIZE (64 * 1024)
-
-/* Provisioned heap size */
-#define OPTEE_SP_HEAP_SIZE (32 * 1024)
-
-#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/protected-storage/opteesp/sp.c b/deployments/protected-storage/opteesp/sp.c
deleted file mode 100644
index af75d8932..000000000
--- a/deployments/protected-storage/opteesp/sp.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "sp.h"
-#include <ffa_api.h>
-#include <components/rpc/common/endpoint/rpc_interface.h>
-#include <components/rpc/ffarpc/endpoint/ffarpc_call_ep.h>
-#include <components/service/secure_storage/factory/storage_factory.h>
-#include <components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h>
-#include <sp_api.h>
-#include <sp_messaging.h>
-#include <sp_rxtx.h>
-#include <trace.h>
-
-uint16_t own_id = 0;
-static uint8_t tx_buffer[4096] __aligned(4096);
-static uint8_t rx_buffer[4096] __aligned(4096);
-
-void sp_main(struct ffa_init_info *init_info)
-{
- ffa_result ffa_res;
- sp_result sp_res;
- struct rpc_interface *secure_storage_iface;
- struct ffa_call_ep ffa_call_ep;
- struct sp_msg req_msg = { 0 };
- struct sp_msg resp_msg = { 0 };
- struct secure_storage_provider secure_storage_provider;
- struct storage_backend *storage_backend;
-
- /* Boot */
- (void) init_info;
-
- ffa_res = ffa_id_get(&own_id);
- if (ffa_res != FFA_OK) {
- EMSG("id get error: %d", ffa_res);
- }
-
- sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
- if (sp_res != SP_RESULT_OK) {
- EMSG("rxtx map error: %d", sp_res);
- }
-
- storage_backend = storage_factory_create(storage_factory_security_class_PROTECTED);
- secure_storage_iface = secure_storage_provider_init(&secure_storage_provider, storage_backend);
- ffa_call_ep_init(&ffa_call_ep, secure_storage_iface);
-
- /* End of boot phase */
- sp_msg_wait(&req_msg);
-
- while (1) {
- ffa_call_ep_receive(&ffa_call_ep, &req_msg, &resp_msg);
-
- resp_msg.source_id = req_msg.destination_id;
- resp_msg.destination_id = req_msg.source_id;
-
- sp_msg_send_direct_resp(&resp_msg, &req_msg);
- }
-}
-
-void sp_interrupt_handler(uint32_t interrupt_id)
-{
- (void)interrupt_id;
-}
diff --git a/deployments/protected-storage/opteesp/sp.h b/deployments/protected-storage/opteesp/sp.h
deleted file mode 100644
index 3bb4484ed..000000000
--- a/deployments/protected-storage/opteesp/sp.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_H
-#define SP_H
-
-/* UUID for the Protected Store */
-#define OPTEE_SP_UUID \
- { 0x751bf801, 0x3dde, 0x4768, \
- { 0xa5, 0x14, 0x0f, 0x10, 0xae, 0xed, 0x17, 0x90 } }
-
-#define SP_UUID_BYTES \
- { 0x75, 0x1b, 0xf8, 0x01, 0x3d, 0xde, 0x47, 0x68, \
- 0xa5, 0x14, 0x0f, 0x10, 0xae, 0xed, 0x17, 0x90 }
-
-#endif /* SP_H */
diff --git a/deployments/protected-storage/protected-storage.cmake b/deployments/protected-storage/protected-storage.cmake
new file mode 100644
index 000000000..b08fbb012
--- /dev/null
+++ b/deployments/protected-storage/protected-storage.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "protected-storage"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ components/common/tlv
+ components/service/common/include
+ components/service/common/provider
+ components/service/secure_storage/include
+ components/service/secure_storage/frontend/secure_storage_provider
+ protocols/rpc/common/packed-c
+ protocols/service/secure_storage/packed-c
+)
+
+target_include_directories(protected-storage PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
diff --git a/deployments/psa-api-test/arch_test_runner.c b/deployments/psa-api-test/arch_test_runner.c
index 43ca70380..8fd3dac49 100644
--- a/deployments/psa-api-test/arch_test_runner.c
+++ b/deployments/psa-api-test/arch_test_runner.c
@@ -1,45 +1,155 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <ctype.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
-#include <service_locator.h>
-#include <rpc/common/logging/logging_caller.h>
+#include <stdlib.h>
#include "service_under_test.h"
+#define TEST_ID_OFFSET (5)
+#define TEST_POSTFIX_OFFSET (8)
+#define TEST_ENTRY_LENGTH (9)
+
+
int32_t val_entry(void);
+extern size_t val_get_test_list(uint32_t *test_id_list, size_t size);
+extern void pal_set_custom_test_list(char *custom_test_list);
-static bool option_selected(const char *option_switch, int argc, char *argv[])
+/* Returns whether option_switch is in the argv list and provide its index in the array */
+static bool option_selected(const char *option_switch, int argc, char *argv[], int *index)
{
bool selected = false;
+ *index = 0;
for (int i = 1; (i < argc) && !selected; ++i) {
selected = (strcmp(argv[i], option_switch) == 0);
+ *index = i;
}
return selected;
}
+/* Print the supported command line arguments */
+static void print_help(void)
+{
+ printf("Supported command line arguments:\n\n");
+ printf("\t -l: Print list of tests.\n");
+ printf("\t -t <test_list>: Run only the listed tests (e.g: test_201;test_202;). test_list = ^(test_[0-9]{3};)+ \n");
+ printf("\t -v: Verbose mode.\n");
+ printf("\t -h: Print this help message.\n");
+ printf("\n");
+}
+
+/* Prints the list of selectable psa-api tests */
+static void print_psa_api_tests(void)
+{
+ /* Request the number of tests to find out the size of the area needed to store the test ID-s. */
+ size_t n_test = val_get_test_list(NULL, 0);
+
+ uint32_t *test_id_list = (uint32_t *)calloc(n_test, sizeof(uint32_t));
+
+ if (test_id_list) {
+ n_test = val_get_test_list(test_id_list, n_test);
+
+ printf("Available psa-api tests:\n");
+ for (int i = 0; i < n_test; i++) {
+ printf("\t test_%d;\n", test_id_list[i]);
+ }
+
+ free(test_id_list);
+ }
+ else {
+ printf("Could not allocate enough memory to store the list of tests\n");
+ }
+}
+
+/* Check if the received test list string is formatted as expected */
+static bool is_test_list_wrong(char* test_list)
+{
+ size_t len = strlen(test_list);
+
+ for (unsigned i = 0; i < len; i += TEST_ENTRY_LENGTH) {
+
+ /* Report error when the test entry is not properly finished */
+ if (i + TEST_ENTRY_LENGTH > len) {
+ printf("Expecting \"test_xxx;\" test entry at the %dth character, got \"%s\" instead.\n", i, &test_list[i]);
+ return true;
+ }
+
+ /* Report error at incorrect test entry prefix */
+ if (memcmp(&test_list[i], "test_", TEST_ID_OFFSET)) {
+ printf("Expecting \"test_\" at the %dth character, got \"%.5s\" instead.\n", i, &test_list[i]);
+ return true;
+ }
+
+ /* Report error if the test ID is incorrect */
+ if (!(isdigit(test_list[i + TEST_ID_OFFSET]) &&
+ isdigit(test_list[i + TEST_ID_OFFSET + 1]) &&
+ isdigit(test_list[i + TEST_ID_OFFSET + 2]))) {
+ printf("Expecting three digits at the %dth character, got \"%.3s\" instead.\n",
+ i + TEST_ID_OFFSET,
+ &test_list[i + TEST_ID_OFFSET]);
+ return true;
+ }
+
+ /* Report error at incorrect test entry postfix */
+ if (test_list[i + TEST_POSTFIX_OFFSET] != ';') {
+ printf("Expecting ; at the %dth character, got \"%.1s\" instead.\n",
+ i + TEST_POSTFIX_OFFSET,
+ &test_list[i + TEST_POSTFIX_OFFSET]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Entry point */
int main(int argc, char *argv[])
{
int rval = -1;
- struct logging_caller *selected_call_logger = NULL;
- struct logging_caller call_logger;
+ int option_index = 0;
+
+ /* Print available tests */
+ if (option_selected("-l", argc, argv, &option_index)) {
+ print_psa_api_tests();
+ return 0;
+ }
- logging_caller_init(&call_logger, stdout);
- service_locator_init();
+ /* Create custom test list */
+ if (option_selected("-t", argc, argv, &option_index)) {
+ /* Avoid overindexing of argv and detect if the option is followed by another option */
+ char *test_list_values = argv[option_index + 1];
+ if ((option_index >= argc) || (test_list_values[0] == '-')) {
+ printf("Testlist string is expected after -t argument!\n");
+ return -1;
+ }
+
+ if (is_test_list_wrong(test_list_values)) {
+ printf("Testlist string is not valid!\n");
+ print_psa_api_tests();
+ return -1;
+ }
+
+ /* Filter tests */
+ pal_set_custom_test_list(test_list_values);
+ }
- /* Check command line options */
- if (option_selected("-l", argc, argv)) selected_call_logger = &call_logger;
+ /* Print help */
+ if (option_selected("-h", argc, argv, &option_index)) {
+ print_help();
+ return 0;
+ }
/* Locate service under test */
- rval = locate_service_under_test(selected_call_logger);
+ rval = locate_service_under_test();
/* Run tests */
if (!rval) {
@@ -53,7 +163,5 @@ int main(int argc, char *argv[])
printf("Failed to locate service under test. Error code: %d\n", rval);
}
- logging_caller_deinit(&call_logger);
-
return rval;
}
diff --git a/deployments/psa-api-test/crypto/arm-linux/CMakeLists.txt b/deployments/psa-api-test/crypto/arm-linux/CMakeLists.txt
index e97830efb..2ef630335 100644
--- a/deployments/psa-api-test/crypto/arm-linux/CMakeLists.txt
+++ b/deployments/psa-api-test/crypto/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../../deployment.cmake REQUIRED)
include(../../psa-api-test-config.cmake REQUIRED)
diff --git a/deployments/psa-api-test/crypto/crypto_locator.c b/deployments/psa-api-test/crypto/crypto_locator.c
index 7f58d4ab3..c57a50199 100644
--- a/deployments/psa-api-test/crypto/crypto_locator.c
+++ b/deployments/psa-api-test/crypto/crypto_locator.c
@@ -7,42 +7,31 @@
#include <stddef.h>
#include <service_locator.h>
#include <service/crypto/client/psa/psa_crypto_client.h>
-#include <service/discovery/client/discovery_client.h>
#include <protocols/rpc/common/packed-c/encoding.h>
#include "../service_under_test.h"
/* RPC context */
-static rpc_session_handle session_handle = NULL;
-static struct service_context *crypto_service_context = NULL;
+static struct rpc_caller_session *session = NULL;
+static struct service_context *attestation_service_context = NULL;
-int locate_service_under_test(struct logging_caller *call_logger)
+int locate_service_under_test(void)
{
int status = -1;
- if (!session_handle && !crypto_service_context) {
+ if (!session && !attestation_service_context) {
- struct rpc_caller *caller;
+ service_locator_init();
- crypto_service_context =
- service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ attestation_service_context =
+ service_locator_query("sn:trustedfirmware.org:crypto:0");
- if (crypto_service_context) {
+ if (attestation_service_context) {
- session_handle =
- service_context_open(crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+ session = service_context_open(attestation_service_context);
- if (session_handle) {
+ if (session) {
- if (call_logger) {
-
- psa_crypto_client_init(logging_caller_attach(call_logger, caller));
- }
- else {
-
- psa_crypto_client_init(caller);
- }
-
- discovery_client_get_service_info(psa_crypto_client_base());
+ psa_crypto_client_init(session);
status = 0;
}
@@ -57,19 +46,21 @@ int locate_service_under_test(struct logging_caller *call_logger)
return status;
}
-void relinquish_service_under_test(void)
+int relinquish_service_under_test(void)
{
psa_crypto_client_deinit();
- if (crypto_service_context && session_handle) {
+ if (attestation_service_context && session) {
- service_context_close(crypto_service_context, session_handle);
- session_handle = NULL;
+ service_context_close(attestation_service_context, session);
+ session = NULL;
}
- if (crypto_service_context) {
+ if (attestation_service_context) {
- service_context_relinquish(crypto_service_context);
- crypto_service_context = NULL;
+ service_context_relinquish(attestation_service_context);
+ attestation_service_context = NULL;
}
+
+ return 0;
}
diff --git a/deployments/psa-api-test/crypto/linux-pc/CMakeLists.txt b/deployments/psa-api-test/crypto/linux-pc/CMakeLists.txt
index e2dd31158..b99604a2d 100644
--- a/deployments/psa-api-test/crypto/linux-pc/CMakeLists.txt
+++ b/deployments/psa-api-test/crypto/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../../deployment.cmake REQUIRED)
include(../../psa-api-test-config.cmake REQUIRED)
diff --git a/deployments/psa-api-test/initial_attestation/arm-linux/CMakeLists.txt b/deployments/psa-api-test/initial_attestation/arm-linux/CMakeLists.txt
index 0dc18f21f..da8e18542 100644
--- a/deployments/psa-api-test/initial_attestation/arm-linux/CMakeLists.txt
+++ b/deployments/psa-api-test/initial_attestation/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../../deployment.cmake REQUIRED)
include(../../psa-api-test-config.cmake REQUIRED)
diff --git a/deployments/psa-api-test/initial_attestation/iat-api-test.cmake b/deployments/psa-api-test/initial_attestation/iat-api-test.cmake
index 1d2c515c1..88b5fb939 100644
--- a/deployments/psa-api-test/initial_attestation/iat-api-test.cmake
+++ b/deployments/psa-api-test/initial_attestation/iat-api-test.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -15,7 +15,7 @@ set(TS_ARCH_TEST_SUITE INITIAL_ATTESTATION CACHE STRING "Arch test suite")
# Set additional defines needed for build.
#-------------------------------------------------------------------------------
list(APPEND PSA_ARCH_TEST_EXTERNAL_DEFS
- -DPSA_ALG_MD4=0x02000002)
+ -DPSA_ALG_MD4=0x02000002 -DPLATFORM_HAS_ATTEST_PK)
#-------------------------------------------------------------------------------
# The arch test build system puts its build output under a test suite specific
@@ -25,7 +25,7 @@ list(APPEND PSA_ARCH_TEST_EXTERNAL_DEFS
set(TS_ARCH_TEST_BUILD_SUBDIR initial_attestation CACHE STRING "Arch test build subdirectory")
#-------------------------------------------------------------------------------
-# Add attestation specific components.
+# Attestation specific components.
#
#-------------------------------------------------------------------------------
add_components(
@@ -46,14 +46,11 @@ target_sources(${PROJECT_NAME} PRIVATE
#
#-------------------------------------------------------------------------------
-# Configuration for mbedcrypto
-set(MBEDTLS_USER_CONFIG_FILE
- "${TS_ROOT}/components/service/crypto/client/cpp/config_mbedtls_user.h"
+# MbedTLS used for token verification
+set(MBEDTLS_USER_CONFIG_FILE "${TS_ROOT}/external/MbedTLS/config/crypto_posix.h"
CACHE STRING "Configuration file for mbedcrypto")
-
-# Mbed TLS provides libmbedcrypto
include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(${PROJECT_NAME} PRIVATE mbedcrypto)
+target_link_libraries(${PROJECT_NAME} PRIVATE MbedTLS::mbedcrypto)
#-------------------------------------------------------------------------------
# Advertise PSA API include paths to PSA Arch tests
diff --git a/deployments/psa-api-test/initial_attestation/iat_locator.c b/deployments/psa-api-test/initial_attestation/iat_locator.c
index 8859497d2..1852fea27 100644
--- a/deployments/psa-api-test/initial_attestation/iat_locator.c
+++ b/deployments/psa-api-test/initial_attestation/iat_locator.c
@@ -13,42 +13,31 @@
#include "../service_under_test.h"
/* RPC context */
-static rpc_session_handle session_handle = NULL;
-static struct service_context *crypto_service_context = NULL;
+static struct rpc_caller_session *session = NULL;
+static struct service_context *attestation_service_context = NULL;
-int locate_service_under_test(struct logging_caller *call_logger)
+int locate_service_under_test(void)
{
int status = -1;
/* Attestation tests depend on PSA crypto so ensure library is initialised */
psa_status_t psa_status = psa_crypto_init();
- if ((psa_status == PSA_SUCCESS) && !session_handle && !crypto_service_context) {
+ if ((psa_status == PSA_SUCCESS) && !session && !attestation_service_context) {
- struct rpc_caller *caller;
+ service_locator_init();
- crypto_service_context =
- service_locator_query("sn:trustedfirmware.org:attestation:0", &status);
+ attestation_service_context =
+ service_locator_query("sn:trustedfirmware.org:attestation:0");
- if (crypto_service_context) {
+ if (attestation_service_context) {
- session_handle =
- service_context_open(crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+ session = service_context_open(attestation_service_context);
- if (session_handle) {
+ if (session) {
- if (call_logger) {
-
- struct rpc_caller *stacked_caller = logging_caller_attach(call_logger, caller);
-
- psa_iat_client_init(stacked_caller);
- attest_provision_client_init(stacked_caller);
- }
- else {
-
- psa_iat_client_init(caller);
- attest_provision_client_init(caller);
- }
+ psa_iat_client_init(session);
+ attest_provision_client_init(session);
status = 0;
}
@@ -63,20 +52,22 @@ int locate_service_under_test(struct logging_caller *call_logger)
return status;
}
-void relinquish_service_under_test(void)
+int relinquish_service_under_test(void)
{
psa_iat_client_deinit();
attest_provision_client_deinit();
- if (crypto_service_context && session_handle) {
+ if (attestation_service_context && session) {
- service_context_close(crypto_service_context, session_handle);
- session_handle = NULL;
+ service_context_close(attestation_service_context, session);
+ session = NULL;
}
- if (crypto_service_context) {
+ if (attestation_service_context) {
- service_context_relinquish(crypto_service_context);
- crypto_service_context = NULL;
+ service_context_relinquish(attestation_service_context);
+ attestation_service_context = NULL;
}
+
+ return 0;
}
diff --git a/deployments/psa-api-test/initial_attestation/linux-pc/CMakeLists.txt b/deployments/psa-api-test/initial_attestation/linux-pc/CMakeLists.txt
index 143012f39..b7e7a76bf 100644
--- a/deployments/psa-api-test/initial_attestation/linux-pc/CMakeLists.txt
+++ b/deployments/psa-api-test/initial_attestation/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../../deployment.cmake REQUIRED)
include(../../psa-api-test-config.cmake REQUIRED)
diff --git a/deployments/psa-api-test/internal_trusted_storage/arm-linux/CMakeLists.txt b/deployments/psa-api-test/internal_trusted_storage/arm-linux/CMakeLists.txt
index 1c2e4eaeb..5ccd66556 100644
--- a/deployments/psa-api-test/internal_trusted_storage/arm-linux/CMakeLists.txt
+++ b/deployments/psa-api-test/internal_trusted_storage/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../../deployment.cmake REQUIRED)
include(../../psa-api-test-config.cmake REQUIRED)
diff --git a/deployments/psa-api-test/internal_trusted_storage/its-api-test.cmake b/deployments/psa-api-test/internal_trusted_storage/its-api-test.cmake
index b5d7e48ed..d373e19bd 100644
--- a/deployments/psa-api-test/internal_trusted_storage/its-api-test.cmake
+++ b/deployments/psa-api-test/internal_trusted_storage/its-api-test.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -19,7 +19,7 @@ set(TS_ARCH_TEST_SUITE INTERNAL_TRUSTED_STORAGE CACHE STRING "Arch test suite")
set(TS_ARCH_TEST_BUILD_SUBDIR storage CACHE STRING "Arch test build subdirectory")
#-------------------------------------------------------------------------------
-# Crypto specific components
+# Internal trusted storage specific components
#
#-------------------------------------------------------------------------------
add_components(
diff --git a/deployments/psa-api-test/internal_trusted_storage/its_locator.c b/deployments/psa-api-test/internal_trusted_storage/its_locator.c
index e1003285d..7119d2106 100644
--- a/deployments/psa-api-test/internal_trusted_storage/its_locator.c
+++ b/deployments/psa-api-test/internal_trusted_storage/its_locator.c
@@ -12,40 +12,32 @@
#include "../service_under_test.h"
/* RPC context */
-static rpc_session_handle session_handle = NULL;
+static struct rpc_caller_session *session = NULL;
static struct service_context *ps_service_context = NULL;
static struct secure_storage_client storage_client;
-int locate_service_under_test(struct logging_caller *call_logger)
+int locate_service_under_test(void)
{
int status = -1;
- if (!session_handle && !ps_service_context) {
+ service_locator_init();
- struct rpc_caller *caller;
+ if (!session && !ps_service_context) {
ps_service_context =
- service_locator_query("sn:trustedfirmware.org:internal-trusted-storage:0", &status);
+ service_locator_query("sn:trustedfirmware.org:internal-trusted-storage:0");
if (ps_service_context) {
- session_handle =
- service_context_open(ps_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+ session =
+ service_context_open(ps_service_context);
- if (session_handle) {
+ if (session) {
struct storage_backend *storage_backend = NULL;
status = -1;
- if (call_logger) {
-
- storage_backend = secure_storage_client_init(&storage_client,
- logging_caller_attach(call_logger, caller));
- }
- else {
-
- storage_backend = secure_storage_client_init(&storage_client, caller);
- }
+ storage_backend = secure_storage_client_init(&storage_client, session);
if (storage_backend) {
@@ -61,15 +53,15 @@ int locate_service_under_test(struct logging_caller *call_logger)
return status;
}
-void relinquish_service_under_test(void)
+int relinquish_service_under_test(void)
{
psa_its_frontend_init(NULL);
secure_storage_client_deinit(&storage_client);
- if (ps_service_context && session_handle) {
+ if (ps_service_context && session) {
- service_context_close(ps_service_context, session_handle);
- session_handle = NULL;
+ service_context_close(ps_service_context, session);
+ session = NULL;
}
if (ps_service_context) {
@@ -77,4 +69,6 @@ void relinquish_service_under_test(void)
service_context_relinquish(ps_service_context);
ps_service_context = NULL;
}
+
+ return 0;
}
diff --git a/deployments/psa-api-test/internal_trusted_storage/linux-pc/CMakeLists.txt b/deployments/psa-api-test/internal_trusted_storage/linux-pc/CMakeLists.txt
index dd350b281..a123e3004 100644
--- a/deployments/psa-api-test/internal_trusted_storage/linux-pc/CMakeLists.txt
+++ b/deployments/psa-api-test/internal_trusted_storage/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../../deployment.cmake REQUIRED)
include(../../psa-api-test-config.cmake REQUIRED)
diff --git a/deployments/psa-api-test/protected_storage/arm-linux/CMakeLists.txt b/deployments/psa-api-test/protected_storage/arm-linux/CMakeLists.txt
index 5611d5019..412833f31 100644
--- a/deployments/psa-api-test/protected_storage/arm-linux/CMakeLists.txt
+++ b/deployments/psa-api-test/protected_storage/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../../deployment.cmake REQUIRED)
include(../../psa-api-test-config.cmake REQUIRED)
diff --git a/deployments/psa-api-test/protected_storage/linux-pc/CMakeLists.txt b/deployments/psa-api-test/protected_storage/linux-pc/CMakeLists.txt
index 482c3e09e..2131d34c2 100644
--- a/deployments/psa-api-test/protected_storage/linux-pc/CMakeLists.txt
+++ b/deployments/psa-api-test/protected_storage/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../../deployment.cmake REQUIRED)
include(../../psa-api-test-config.cmake REQUIRED)
diff --git a/deployments/psa-api-test/protected_storage/ps-api-test.cmake b/deployments/psa-api-test/protected_storage/ps-api-test.cmake
index 5a733b8dc..9fa88fe53 100644
--- a/deployments/psa-api-test/protected_storage/ps-api-test.cmake
+++ b/deployments/psa-api-test/protected_storage/ps-api-test.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -19,7 +19,7 @@ set(TS_ARCH_TEST_SUITE PROTECTED_STORAGE CACHE STRING "Arch test suite")
set(TS_ARCH_TEST_BUILD_SUBDIR storage CACHE STRING "Arch test build subdirectory")
#-------------------------------------------------------------------------------
-# Crypto specific components
+# Protected storage specific components
#
#-------------------------------------------------------------------------------
add_components(
diff --git a/deployments/psa-api-test/protected_storage/ps_locator.c b/deployments/psa-api-test/protected_storage/ps_locator.c
index 3ed35b6d4..aba854773 100644
--- a/deployments/psa-api-test/protected_storage/ps_locator.c
+++ b/deployments/psa-api-test/protected_storage/ps_locator.c
@@ -12,40 +12,30 @@
#include "../service_under_test.h"
/* RPC context */
-static rpc_session_handle session_handle = NULL;
+static struct rpc_caller_session *session = NULL;
static struct service_context *ps_service_context = NULL;
static struct secure_storage_client storage_client;
-int locate_service_under_test(struct logging_caller *call_logger)
+int locate_service_under_test(void)
{
int status = -1;
- if (!session_handle && !ps_service_context) {
+ if (!session && !ps_service_context) {
- struct rpc_caller *caller;
+ service_locator_init();
ps_service_context =
- service_locator_query("sn:trustedfirmware.org:protected-storage:0", &status);
+ service_locator_query("sn:trustedfirmware.org:protected-storage:0");
if (ps_service_context) {
- session_handle =
- service_context_open(ps_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+ session = service_context_open(ps_service_context);
- if (session_handle) {
+ if (session) {
struct storage_backend *storage_backend = NULL;
- status = -1;
- if (call_logger) {
-
- storage_backend = secure_storage_client_init(&storage_client,
- logging_caller_attach(call_logger, caller));
- }
- else {
-
- storage_backend = secure_storage_client_init(&storage_client, caller);
- }
+ storage_backend = secure_storage_client_init(&storage_client, session);
if (storage_backend) {
@@ -61,15 +51,15 @@ int locate_service_under_test(struct logging_caller *call_logger)
return status;
}
-void relinquish_service_under_test(void)
+int relinquish_service_under_test(void)
{
psa_ps_frontend_init(NULL);
secure_storage_client_deinit(&storage_client);
- if (ps_service_context && session_handle) {
+ if (ps_service_context && session) {
- service_context_close(ps_service_context, session_handle);
- session_handle = NULL;
+ service_context_close(ps_service_context, session);
+ session = NULL;
}
if (ps_service_context) {
@@ -77,4 +67,6 @@ void relinquish_service_under_test(void)
service_context_relinquish(ps_service_context);
ps_service_context = NULL;
}
-}
+
+ return 0;
+} \ No newline at end of file
diff --git a/deployments/psa-api-test/psa-api-test.cmake b/deployments/psa-api-test/psa-api-test.cmake
index d58620fea..739ed262d 100644
--- a/deployments/psa-api-test/psa-api-test.cmake
+++ b/deployments/psa-api-test/psa-api-test.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -12,14 +12,14 @@
#-------------------------------------------------------------------------------
# Use libts for locating and accessing services. An appropriate version of
-# libts will be imported for the enviroment in which service tests are
+# libts will be imported for the environment in which service tests are
# deployed.
#-------------------------------------------------------------------------------
include(${TS_ROOT}/deployments/libts/libts-import.cmake)
-target_link_libraries(${PROJECT_NAME} PRIVATE libts)
+target_link_libraries(${PROJECT_NAME} PRIVATE libts::ts)
#-------------------------------------------------------------------------------
-# Components that are common accross all deployments
+# Components that are common across all deployments
#
#-------------------------------------------------------------------------------
add_components(
@@ -29,9 +29,6 @@ add_components(
"components/common/tlv"
"components/service/common/client"
"components/service/common/include"
- "components/service/discovery/client"
- "components/rpc/common/caller"
- "components/rpc/common/logging"
)
target_sources(${PROJECT_NAME} PRIVATE
diff --git a/deployments/psa-api-test/service_under_test.h b/deployments/psa-api-test/service_under_test.h
index 29f99f751..834384e69 100644
--- a/deployments/psa-api-test/service_under_test.h
+++ b/deployments/psa-api-test/service_under_test.h
@@ -7,8 +7,6 @@
#ifndef SERVICE_UNDER_TEST_H
#define SERVICE_UNDER_TEST_H
-#include <rpc/common/logging/logging_caller.h>
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -19,12 +17,12 @@ extern "C" {
* associate an RPC Caller with the singleton PSA API client used by
* the API tests.
*/
-int locate_service_under_test(struct logging_caller *call_logger);
+int locate_service_under_test(void);
/**
* Reliquish the RPC session when the test run is complete.
*/
-void relinquish_service_under_test(void);
+int relinquish_service_under_test(void);
#ifdef __cplusplus
diff --git a/deployments/se-proxy/config/corstone1000-opteesp/CMakeLists.txt b/deployments/se-proxy/config/corstone1000-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..2c0da0e97
--- /dev/null
+++ b/deployments/se-proxy/config/corstone1000-opteesp/CMakeLists.txt
@@ -0,0 +1,91 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/corstone1000" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the se-proxy deployment for Corstone1000
+# using the "opteesp" environment.
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(se-proxy)
+target_include_directories(se-proxy PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "46bb39d1-b4d9-45b5-88ff-040027dab249")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "SEPROXY" CACHE STRING "Trace prefix")
+
+target_include_directories(se-proxy PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the opteesp environment.
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "se-proxy"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/se_proxy_sp.cmake REQUIRED)
+include(../../infra/corstone1000/infra.cmake REQUIRED)
+include(../../se-proxy.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "se-proxy")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(se-proxy PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(se-proxy PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+#TODO: api headers
+
+install(TARGETS se-proxy
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+get_property(_PROTO_FILES TARGET se-proxy PROPERTY PROTOBUF_FILES)
+install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "se-proxy"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_se-proxy.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in b/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in
new file mode 100644
index 000000000..cc42929d5
--- /dev/null
+++ b/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "SE Proxy";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+
+ device-regions {
+ compatible = "arm,ffa-manifest-device-regions";
+ mhu-sender {
+ /* Armv8 A Foundation Platform values */
+ base-address = <0x00000000 0x1b820000>;
+ pages-count = <16>;
+ attributes = <0x3>; /* read-write */
+ };
+ mhu-receiver {
+ /* Armv8 A Foundation Platform values */
+ base-address = <0x00000000 0x1b830000>;
+ pages-count = <16>;
+ attributes = <0x3>; /* read-write */
+ };
+ openamp-virtio {
+ /* Armv8 A Foundation Platform values */
+ base-address = <0x00000000 0x88000000>;
+ pages-count = <256>;
+ attributes = <0x3>; /* read-write */
+ };
+ };
+};
diff --git a/deployments/se-proxy/config/corstone1000-opteesp/optee_sp_user_defines.h b/deployments/se-proxy/config/corstone1000-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..efc1dfa92
--- /dev/null
+++ b/deployments/se-proxy/config/corstone1000-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef SP_HEADER_DEFINES_H
+#define SP_HEADER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/se-proxy/config/default-opteesp/CMakeLists.txt b/deployments/se-proxy/config/default-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..77ea841d2
--- /dev/null
+++ b/deployments/se-proxy/config/default-opteesp/CMakeLists.txt
@@ -0,0 +1,93 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the se-proxy deployment for opteesp
+#
+# Builds proxy service providers that communicate with a separate secure element
+# that hosts a set of service endpoints. This deployment is for running in an
+# SEL0 secure partition hosted by OPTEE in the role of SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(se-proxy)
+target_include_directories(se-proxy PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_BIN_UUID_CANON "46bb39d1-b4d9-45b5-88ff-040027dab249")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "SEPROXY" CACHE STRING "Trace prefix")
+
+target_include_directories(se-proxy PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the opteesp environment.
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "se-proxy"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/se_proxy_sp.cmake REQUIRED)
+include(../../infra/stub/stub.cmake REQUIRED)
+include(../../se-proxy.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "se-proxy")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(se-proxy PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(se-proxy PRIVATE
+ -std=c99
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+#TODO: api headers
+
+install(TARGETS se-proxy
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+get_property(_PROTO_FILES TARGET se-proxy PROPERTY PROTOBUF_FILES)
+install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "se-proxy"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_se-proxy.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/se-proxy/opteesp/default_se-proxy.dts.in b/deployments/se-proxy/config/default-opteesp/default_se-proxy.dts.in
index 961071adb..902017c35 100644
--- a/deployments/se-proxy/opteesp/default_se-proxy.dts.in
+++ b/deployments/se-proxy/config/default-opteesp/default_se-proxy.dts.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,5 +15,7 @@
exception-level = <1>; /* S-EL0 */
execution-state = <0>; /* AArch64 */
xlat-granule = <0>; /* 4KiB */
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
};
diff --git a/deployments/se-proxy/config/default-opteesp/optee_sp_user_defines.h b/deployments/se-proxy/config/default-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..598cbccf9
--- /dev/null
+++ b/deployments/se-proxy/config/default-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef SP_HEADER_DEFINES_H
+#define SP_HEADER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/se-proxy/config/default-sp/CMakeLists.txt b/deployments/se-proxy/config/default-sp/CMakeLists.txt
new file mode 100644
index 000000000..70d40739d
--- /dev/null
+++ b/deployments/se-proxy/config/default-sp/CMakeLists.txt
@@ -0,0 +1,92 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the se-proxy deployment for generic sp
+# environment.
+#
+# Builds proxy service providers that communicate with a separate secure element
+# that hosts a set of service endpoints. This deployment is for running in an
+# SEL0 secure partition hosted by any SPM.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(se-proxy)
+target_include_directories(se-proxy PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_NAME "se-proxy")
+set(SP_BIN_UUID_CANON "46bb39d1-b4d9-45b5-88ff-040027dab249")
+set(SP_FFA_UUID_CANON "${TS_RPC_UUID_CANON}")
+set(TRACE_PREFIX "SEPROXY" CACHE STRING "Trace prefix")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the opteesp environment.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "se-proxy"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+include(../../env/commonsp/se_proxy_sp.cmake REQUIRED)
+include(../../infra/stub/stub.cmake REQUIRED)
+include(../../se-proxy.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "se-proxy")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(se-proxy PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(se-proxy PRIVATE
+ -std=c99
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET se-proxy NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET se-proxy NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS se-proxy
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake REQUIRED)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/se-proxy/config/default-sp/default_se-proxy.dts.in b/deployments/se-proxy/config/default-sp/default_se-proxy.dts.in
new file mode 100644
index 000000000..3b66f9258
--- /dev/null
+++ b/deployments/se-proxy/config/default-sp/default_se-proxy.dts.in
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "SE Proxy";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ #include "@EXPORT_DTS_MEM_REGIONS@"
+ };
+};
diff --git a/deployments/se-proxy/env/commonsp/se_proxy_sp.c b/deployments/se-proxy/env/commonsp/se_proxy_sp.c
new file mode 100644
index 000000000..155e94863
--- /dev/null
+++ b/deployments/se-proxy/env/commonsp/se_proxy_sp.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
+#include "components/rpc/ts_rpc/endpoint/sp/ts_rpc_endpoint_sp.h"
+#include "config/ramstore/config_ramstore.h"
+#include "config/loader/sp/sp_config_loader.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+#include "deployments/se-proxy/infra/service_proxy_factory.h"
+#include "deployments/se-proxy/se_proxy_interfaces.h"
+
+static bool sp_init(uint16_t *own_sp_id);
+
+void __noreturn sp_main(union ffa_boot_info *boot_info)
+{
+ struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
+ struct sp_msg req_msg = { 0 };
+ struct sp_msg resp_msg = { 0 };
+ struct rpc_service_interface *rpc_iface = NULL;
+ uint16_t own_id = 0;
+ sp_result result = SP_RESULT_INTERNAL_ERROR;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Boot phase */
+ if (!sp_init(&own_id)) {
+ EMSG("Failed to init SP");
+ goto fatal_error;
+ }
+
+ config_ramstore_init();
+
+ if (!sp_config_load(boot_info)) {
+ EMSG("Failed to load SP config");
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_init(&rpc_endpoint, 4, 16);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to initialize RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /* Create service proxies */
+ rpc_iface = its_proxy_create();
+ if (!rpc_iface) {
+ EMSG("Failed to create ITS proxy");
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, rpc_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_iface = ps_proxy_create();
+ if (!rpc_iface) {
+ EMSG("Failed to create PS proxy");
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, rpc_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_iface = crypto_proxy_create();
+ if (!rpc_iface) {
+ EMSG("Failed to create Crypto proxy");
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, rpc_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ rpc_iface = attest_proxy_create();
+ if (!rpc_iface) {
+ EMSG("Failed to create Attestation proxy");
+ goto fatal_error;
+ }
+
+ rpc_status = ts_rpc_endpoint_sp_add_service(&rpc_endpoint, rpc_iface);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Failed to add service to RPC endpoint: %d", rpc_status);
+ goto fatal_error;
+ }
+
+ /* End of boot phase */
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ ts_rpc_endpoint_sp_receive(&rpc_endpoint, &req_msg, &resp_msg);
+
+ result = sp_msg_send_direct_resp(&resp_msg, &req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = sp_msg_wait(&req_msg);
+ if (result != SP_RESULT_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("SE proxy SP error");
+ while (1) {}
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
+
+static bool sp_init(uint16_t *own_id)
+{
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ static uint8_t tx_buffer[4096] __aligned(4096);
+ static uint8_t rx_buffer[4096] __aligned(4096);
+
+ sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", sp_res);
+ return false;
+ }
+
+ sp_res = sp_discovery_own_id_get(own_id);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", sp_res);
+ return false;
+ }
+
+ return true;
+}
diff --git a/deployments/se-proxy/env/commonsp/se_proxy_sp.cmake b/deployments/se-proxy/env/commonsp/se_proxy_sp.cmake
new file mode 100644
index 000000000..c052f4200
--- /dev/null
+++ b/deployments/se-proxy/env/commonsp/se_proxy_sp.cmake
@@ -0,0 +1,29 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the se-proxy service provider
+# within a secure partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for se-proxy sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "se-proxy"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/endpoint/sp"
+)
+
+target_sources(se-proxy PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/se_proxy_sp.c
+)
diff --git a/deployments/se-proxy/env/commonsp/se_proxy_sp.h b/deployments/se-proxy/env/commonsp/se_proxy_sp.h
new file mode 100644
index 000000000..4ae235573
--- /dev/null
+++ b/deployments/se-proxy/env/commonsp/se_proxy_sp.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SE_PROXY_SP_H
+#define SE_PROXY_SP_H
+
+#endif /* SE_PROXY_SP_H */
diff --git a/deployments/se-proxy/infra/corstone1000/infra.cmake b/deployments/se-proxy/infra/corstone1000/infra.cmake
new file mode 100644
index 000000000..4e7e2bd58
--- /dev/null
+++ b/deployments/se-proxy/infra/corstone1000/infra.cmake
@@ -0,0 +1,34 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# A stub infrastructure for the se-proxy. Infrastructure dependencies are all
+# realized with stub components that do absolutely nothing.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "se-proxy"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/rpc/common/caller"
+ "components/rpc/psa_ipc"
+ "components/messaging/openamp/sp"
+ "components/service/attestation/client/psa_ipc"
+ "components/service/attestation/key_mngr/local"
+ "components/service/attestation/reporter/psa_ipc"
+ "components/service/crypto/backend/psa_ipc"
+ "components/service/secure_storage/backend/secure_storage_ipc"
+)
+
+# OpenAMP
+include(${TS_ROOT}/external/openamp/openamp.cmake)
+target_link_libraries(se-proxy PRIVATE openamp)
+
+target_sources(se-proxy PRIVATE
+
+ ${CMAKE_CURRENT_LIST_DIR}/service_proxy_factory.c
+)
diff --git a/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c b/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
new file mode 100644
index 000000000..6885f928d
--- /dev/null
+++ b/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <psa/sid.h>
+#include "rpc/common/endpoint/rpc_service_interface.h"
+#include <rpc/psa_ipc/caller/sp/psa_ipc_caller.h>
+#include <service/attestation/provider/attest_provider.h>
+#include <service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h>
+#include <service/crypto/factory/crypto_provider_factory.h>
+#include <service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h>
+#include "service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
+#include <trace.h>
+
+/* backends */
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h>
+#include <service/attestation/client/psa/iat_client.h>
+
+static const struct rpc_uuid dummy_uuid = { 0 };
+
+struct rpc_service_interface *attest_proxy_create(void)
+{
+ struct rpc_service_interface *attest_iface = NULL;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Static objects for proxy instance */
+ static struct rpc_caller_interface psa_ipc = { 0 };
+ static struct rpc_caller_session rpc_session = { 0 };
+ static struct attest_provider attest_provider = { 0 };
+
+ rpc_status = psa_ipc_caller_init(&psa_ipc);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ /* Initialize the service provider */
+ attest_iface = attest_provider_init(&attest_provider);
+ psa_iat_client_init(&rpc_session);
+
+ attest_provider_register_serializer(&attest_provider,
+ packedc_attest_provider_serializer_instance());
+
+ return attest_iface;
+}
+
+struct rpc_service_interface *crypto_proxy_create(void)
+{
+ struct rpc_service_interface *crypto_iface = NULL;
+ struct crypto_provider *crypto_provider;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+
+ /* Static objects for proxy instance */
+ static struct rpc_caller_interface psa_ipc = { 0 };
+ static struct rpc_caller_session rpc_session = { 0 };
+
+ rpc_status = psa_ipc_caller_init(&psa_ipc);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ if (crypto_ipc_backend_init(&rpc_session) != PSA_SUCCESS)
+ return NULL;
+
+ crypto_provider = crypto_provider_factory_create();
+ crypto_iface = service_provider_get_rpc_interface(&crypto_provider->base_provider);
+
+ return crypto_iface;
+}
+
+struct rpc_service_interface *ps_proxy_create(void)
+{
+ static struct secure_storage_provider ps_provider;
+ static struct secure_storage_ipc ps_backend;
+ struct storage_backend *backend;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ const struct rpc_uuid ps_uuid = { .uuid = TS_PSA_PROTECTED_STORAGE_UUID };
+
+ /* Static objects for proxy instance */
+ static struct rpc_caller_interface psa_ipc = { 0 };
+ static struct rpc_caller_session rpc_session = { 0 };
+
+ rpc_status = psa_ipc_caller_init(&psa_ipc);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ backend = secure_storage_ipc_init(&ps_backend, &rpc_session);
+ ps_backend.service_handle = TFM_PROTECTED_STORAGE_SERVICE_HANDLE;
+
+ return secure_storage_provider_init(&ps_provider, backend, &ps_uuid);
+}
+
+struct rpc_service_interface *its_proxy_create(void)
+{
+ static struct secure_storage_provider its_provider;
+ static struct secure_storage_ipc its_backend;
+ struct storage_backend *backend;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ const struct rpc_uuid its_uuid = { .uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID };
+
+ /* Static objects for proxy instance */
+ static struct rpc_caller_interface psa_ipc = { 0 };
+ static struct rpc_caller_session rpc_session = { 0 };
+
+ rpc_status = psa_ipc_caller_init(&psa_ipc);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ backend = secure_storage_ipc_init(&its_backend, &rpc_session);
+ its_backend.service_handle = TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_HANDLE;
+
+ return secure_storage_provider_init(&its_provider, backend, &its_uuid);
+}
diff --git a/deployments/se-proxy/opteesp/service_proxy_factory.h b/deployments/se-proxy/infra/service_proxy_factory.h
index 298d407a2..caaea79ed 100644
--- a/deployments/se-proxy/opteesp/service_proxy_factory.h
+++ b/deployments/se-proxy/infra/service_proxy_factory.h
@@ -7,16 +7,16 @@
#ifndef SERVICE_PROXY_FACTORY_H
#define SERVICE_PROXY_FACTORY_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "components/rpc/common/endpoint/rpc_service_interface.h"
#ifdef __cplusplus
extern "C" {
#endif
-struct rpc_interface *attest_proxy_create(void);
-struct rpc_interface *crypto_proxy_create(void);
-struct rpc_interface *ps_proxy_create(void);
-struct rpc_interface *its_proxy_create(void);
+struct rpc_service_interface *attest_proxy_create(void);
+struct rpc_service_interface *crypto_proxy_create(void);
+struct rpc_service_interface *ps_proxy_create(void);
+struct rpc_service_interface *its_proxy_create(void);
#ifdef __cplusplus
}
diff --git a/deployments/se-proxy/infra/stub/service_proxy_factory.c b/deployments/se-proxy/infra/stub/service_proxy_factory.c
new file mode 100644
index 000000000..4cec9ce3e
--- /dev/null
+++ b/deployments/se-proxy/infra/stub/service_proxy_factory.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include "rpc/common/endpoint/rpc_service_interface.h"
+#include "service/attestation/provider/attest_provider.h"
+#include "service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h"
+#include "service/crypto/factory/crypto_provider_factory.h"
+#include "service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h"
+#include "service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
+
+/* Stub backends */
+#include <service/crypto/backend/stub/stub_crypto_backend.h>
+#include <service/secure_storage/backend/mock_store/mock_store.h>
+
+struct rpc_service_interface *attest_proxy_create(void)
+{
+ struct rpc_service_interface *attest_iface = NULL;
+
+ /* Static objects for proxy instance */
+ static struct attest_provider attest_provider = { 0 };
+
+ /* Initialize the service provider */
+ attest_iface = attest_provider_init(&attest_provider);
+
+ attest_provider_register_serializer(&attest_provider,
+ packedc_attest_provider_serializer_instance());
+
+ return attest_iface;
+}
+
+struct rpc_service_interface *crypto_proxy_create(void)
+{
+ struct rpc_service_interface *crypto_iface = NULL;
+ struct crypto_provider *crypto_provider = NULL;
+
+ if (stub_crypto_backend_init() == PSA_SUCCESS) {
+
+ crypto_provider = crypto_provider_factory_create();
+ crypto_iface = service_provider_get_rpc_interface(&crypto_provider->base_provider);
+ }
+
+ return crypto_iface;
+}
+
+struct rpc_service_interface *ps_proxy_create(void)
+{
+ static struct mock_store ps_backend;
+ static struct secure_storage_provider ps_provider;
+ const struct rpc_uuid service_uuid = { .uuid = TS_PSA_PROTECTED_STORAGE_UUID };
+
+ struct storage_backend *backend = mock_store_init(&ps_backend);
+
+ return secure_storage_provider_init(&ps_provider, backend, &service_uuid);
+}
+
+struct rpc_service_interface *its_proxy_create(void)
+{
+ static struct mock_store its_backend;
+ static struct secure_storage_provider its_provider;
+ const struct rpc_uuid service_uuid = { .uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID };
+
+ struct storage_backend *backend = mock_store_init(&its_backend);
+
+ return secure_storage_provider_init(&its_provider, backend, &service_uuid);
+}
diff --git a/deployments/se-proxy/infra/stub/stub.cmake b/deployments/se-proxy/infra/stub/stub.cmake
new file mode 100644
index 000000000..a364f8d7a
--- /dev/null
+++ b/deployments/se-proxy/infra/stub/stub.cmake
@@ -0,0 +1,29 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# A stub infrastructure for the se-proxy. Infrastructure dependencies are all
+# realized with stub components that do absolutely nothing.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "se-proxy"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/rpc/dummy"
+ "components/rpc/common/caller"
+ "components/service/attestation/reporter/stub"
+ "components/service/attestation/key_mngr/stub"
+ "components/service/crypto/backend/stub"
+ "components/service/crypto/client/psa"
+ "components/service/secure_storage/backend/mock_store"
+)
+
+target_sources(se-proxy PRIVATE
+
+ ${CMAKE_CURRENT_LIST_DIR}/service_proxy_factory.c
+)
diff --git a/deployments/se-proxy/opteesp/CMakeLists.txt b/deployments/se-proxy/opteesp/CMakeLists.txt
deleted file mode 100644
index 23a5c6205..000000000
--- a/deployments/se-proxy/opteesp/CMakeLists.txt
+++ /dev/null
@@ -1,166 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
-
-# Set default platform.
-set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
-include(../../deployment.cmake REQUIRED)
-
-#-------------------------------------------------------------------------------
-# The CMakeLists.txt for building the se-proxy deployment for opteesp
-#
-# Builds proxy service providers that communicate with a separate secure element
-# that hosts a set of service endpoints. This deployment is for running in an
-# SEL0 secure partition hosted by OPTEE in the role of SPM.
-#-------------------------------------------------------------------------------
-include(${TS_ROOT}/environments/opteesp/env.cmake)
-project(trusted-services LANGUAGES C ASM)
-add_executable(se-proxy)
-target_include_directories(se-proxy PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
-set(SP_UUID "46bb39d1-b4d9-45b5-88ff-040027dab249")
-
-#-------------------------------------------------------------------------------
-# Include SP DEV KIT interface
-#
-#-------------------------------------------------------------------------------
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit REQUIRED)
-sp_dev_kit_configure_linking(TARGET se-proxy DEFINES ARM64=1)
-target_link_libraries(se-proxy PRIVATE ${SP_DEV_KIT_LIBRARIES})
-
-#-------------------------------------------------------------------------------
-# Components that are specific to deployment in the opteesp environment.
-#
-#-------------------------------------------------------------------------------
-add_components(TARGET "se-proxy"
- BASE_DIR ${TS_ROOT}
- COMPONENTS
- "components/common/trace"
- "components/common/utils"
- "protocols/rpc/common/packed-c"
- "protocols/service/secure_storage/packed-c"
- "protocols/service/crypto/protobuf"
- "environments/opteesp"
- "components/common/tlv"
- "components/config/ramstore"
- "components/config/loader/sp"
- "components/messaging/ffa/libsp"
- "components/rpc/ffarpc/endpoint"
- "components/rpc/common/interface"
- "components/rpc/common/demux"
- "components/service/common/include"
- "components/service/common/serializer/protobuf"
- "components/service/common/client"
- "components/service/common/provider"
- "components/service/discovery/provider"
- "components/service/discovery/provider/serializer/packed-c"
- "components/service/crypto/include"
- "components/service/crypto/provider"
- "components/service/crypto/provider/serializer/protobuf"
- "components/service/crypto/provider/serializer/packed-c"
- "components/service/crypto/provider/extension/hash"
- "components/service/crypto/provider/extension/hash/serializer/packed-c"
- "components/service/crypto/provider/extension/cipher"
- "components/service/crypto/provider/extension/cipher/serializer/packed-c"
- "components/service/crypto/provider/extension/key_derivation"
- "components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
- "components/service/crypto/provider/extension/mac"
- "components/service/crypto/provider/extension/mac/serializer/packed-c"
- "components/service/crypto/factory/full"
- "components/service/secure_storage/include"
- "components/service/secure_storage/frontend/secure_storage_provider"
- "components/service/attestation/include"
- "components/service/attestation/provider"
- "components/service/attestation/provider/serializer/packed-c"
-
- # Stub service provider backends
- "components/rpc/dummy"
- "components/rpc/common/caller"
- "components/service/attestation/reporter/stub"
- "components/service/attestation/key_mngr/stub"
- "components/service/crypto/backend/stub"
- "components/service/crypto/client/psa"
- "components/service/secure_storage/backend/mock_store"
-)
-
-target_sources(se-proxy PRIVATE
- se_proxy_sp.c
- service_proxy_factory.c
-)
-
-#-------------------------------------------------------------------------------
-# Set target platform to provide drivers needed by the deployment
-#
-#-------------------------------------------------------------------------------
-add_platform(TARGET "se-proxy")
-
-#-------------------------------------------------------------------------------
-# Components used from external projects
-#
-#-------------------------------------------------------------------------------
-
-# Nanopb
-list(APPEND NANOPB_EXTERNAL_INCLUDE_PATHS ${SP_DEV_KIT_INCLUDE_DIR})
-include(../../../external/nanopb/nanopb.cmake)
-target_link_libraries(se-proxy PRIVATE nanopb::protobuf-nanopb-static)
-protobuf_generate_all(TGT "se-proxy" NAMESPACE "protobuf" BASE_DIR "${TS_ROOT}/protocols")
-
-#################################################################
-
-target_compile_definitions(se-proxy PRIVATE
- ARM64=1
-)
-
-target_include_directories(se-proxy PRIVATE
- ${TS_ROOT}
- ${TS_ROOT}/components
- ${TS_ROOT}/deployments/se-proxy/opteesp
-)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_compile_options(se-proxy PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
- -std=c99
- )
-
- # Options for GCC that control linking
- target_link_options(se-proxy PRIVATE
- -zmax-page-size=4096
- )
- # Options directly for LD, these are not understood by GCC
- target_link_options(se-proxy PRIVATE
- -Wl,--as-needed
- -Wl,--sort-section=alignment
- # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
- )
-endif()
-
-compiler_generate_stripped_elf(TARGET se-proxy NAME "${SP_UUID}.stripped.elf" RES STRIPPED_ELF)
-
-######################################## install
-if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
-endif()
-#TODO: api headers
-
-install(TARGETS se-proxy
- PUBLIC_HEADER DESTINATION ${TS_ENV}/include
- RUNTIME DESTINATION ${TS_ENV}/bin
- )
-install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
-
-get_property(_PROTO_FILES TARGET se-proxy PROPERTY PROTOBUF_FILES)
-install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
-
-
-set(EXPORT_SP_NAME "se-proxy")
-set(EXPORT_SP_UUID ${SP_UUID})
-include(${TS_ROOT}/environments/opteesp/ExportSp.cmake)
diff --git a/deployments/se-proxy/opteesp/optee_sp_user_defines.h b/deployments/se-proxy/opteesp/optee_sp_user_defines.h
deleted file mode 100644
index 3c25e4371..000000000
--- a/deployments/se-proxy/opteesp/optee_sp_user_defines.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_HEADER_DEFINES_H
-#define SP_HEADER_DEFINES_H
-
-/* To get UUID definition */
-#include "se_proxy_sp.h"
-
-#define OPTEE_SP_UUID SE_PROXY_SP_UUID
-#define OPTEE_SP_FLAGS 0
-
-/* Provisioned stack size */
-#define OPTEE_SP_STACK_SIZE (64 * 1024)
-
-/* Provisioned heap size */
-#define OPTEE_SP_HEAP_SIZE (32 * 1024)
-
-#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/se-proxy/opteesp/se_proxy_sp.c b/deployments/se-proxy/opteesp/se_proxy_sp.c
deleted file mode 100644
index ef90d9eee..000000000
--- a/deployments/se-proxy/opteesp/se_proxy_sp.c
+++ /dev/null
@@ -1,94 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#include <rpc/ffarpc/endpoint/ffarpc_call_ep.h>
-#include <rpc/common/demux/rpc_demux.h>
-#include <config/ramstore/config_ramstore.h>
-#include <config/loader/sp/sp_config_loader.h>
-#include <ffa_api.h>
-#include <sp_api.h>
-#include <sp_rxtx.h>
-#include <trace.h>
-#include "service_proxy_factory.h"
-#include "../se_proxy_interfaces.h"
-
-uint16_t own_id = 0; /* !!Needs refactoring as parameter to ffarpc_caller_init */
-
-
-static int sp_init(uint16_t *own_sp_id);
-
-void __noreturn sp_main(struct ffa_init_info *init_info)
-{
- struct ffa_call_ep ffarpc_call_ep;
- struct sp_msg req_msg;
- struct rpc_demux rpc_demux;
- struct rpc_interface *rpc_iface;
-
- /* Boot phase */
- if (sp_init(&own_id) != 0) goto fatal_error;
-
- config_ramstore_init();
- sp_config_load(init_info);
-
- rpc_iface = rpc_demux_init(&rpc_demux);
- ffa_call_ep_init(&ffarpc_call_ep, rpc_iface);
-
- /* Create service proxies */
- rpc_iface = its_proxy_create();
- rpc_demux_attach(&rpc_demux, SE_PROXY_INTERFACE_ID_ITS, rpc_iface);
-
- rpc_iface = ps_proxy_create();
- rpc_demux_attach(&rpc_demux, SE_PROXY_INTERFACE_ID_PS, rpc_iface);
-
- rpc_iface = crypto_proxy_create();
- rpc_demux_attach(&rpc_demux, SE_PROXY_INTERFACE_ID_CRYPTO, rpc_iface);
-
- rpc_iface = attest_proxy_create();
- rpc_demux_attach(&rpc_demux, SE_PROXY_INTERFACE_ID_ATTEST, rpc_iface);
-
- /* End of boot phase */
- sp_msg_wait(&req_msg);
-
- while (1) {
-
- struct sp_msg resp_msg;
-
- ffa_call_ep_receive(&ffarpc_call_ep, &req_msg, &resp_msg);
-
- resp_msg.source_id = req_msg.destination_id;
- resp_msg.destination_id = req_msg.source_id;
-
- sp_msg_send_direct_resp(&resp_msg, &req_msg);
- }
-
-fatal_error:
- /* SP is not viable */
- EMSG("SE proxy SP error");
- while (1) {}
-}
-
-void sp_interrupt_handler(uint32_t interrupt_id)
-{
- (void)interrupt_id;
-}
-
-static int sp_init(uint16_t *own_sp_id)
-{
- int status = -1;
- ffa_result ffa_res;
- sp_result sp_res;
- static uint8_t tx_buffer[4096] __aligned(4096);
- static uint8_t rx_buffer[4096] __aligned(4096);
-
- sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
- if (sp_res == SP_RESULT_OK) {
- ffa_res = ffa_id_get(own_sp_id);
- if (ffa_res == FFA_OK) {
- status = 0;
- }
- }
-
- return status;
-}
diff --git a/deployments/se-proxy/opteesp/se_proxy_sp.h b/deployments/se-proxy/opteesp/se_proxy_sp.h
deleted file mode 100644
index 74bbde46f..000000000
--- a/deployments/se-proxy/opteesp/se_proxy_sp.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SE_PROXY_SP_H
-#define SE_PROXY_SP_H
-
-#define SE_PROXY_SP_UUID \
- {0x46bb39d1, 0xb4d9, 0x45b5, \
- {0x88, 0xff, 0x04, 0x00, 0x27, 0xda, 0xb2, 0x49}}
-
-#define SE_PROXY_SP_UUID_BYTES \
- {0x46, 0xbb, 0x39, 0xd1, 0xb4, 0xd9, 0x45, 0xb5, \
- 0x88, 0xff, 0x04, 0x00, 0x27, 0xda, 0xb2, 0x49}
-
-#endif /* SE_PROXY_SP_H */
diff --git a/deployments/se-proxy/opteesp/service_proxy_factory.c b/deployments/se-proxy/opteesp/service_proxy_factory.c
deleted file mode 100644
index acfb6e887..000000000
--- a/deployments/se-proxy/opteesp/service_proxy_factory.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-#include <rpc/common/endpoint/rpc_interface.h>
-#include <service/attestation/provider/attest_provider.h>
-#include <service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h>
-#include <service/crypto/factory/crypto_provider_factory.h>
-#include <service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h>
-
-/* Stub backends */
-#include <service/crypto/backend/stub/stub_crypto_backend.h>
-#include <service/secure_storage/backend/mock_store/mock_store.h>
-
-struct rpc_interface *attest_proxy_create(void)
-{
- struct rpc_interface *attest_iface;
-
- /* Static objects for proxy instance */
- static struct attest_provider attest_provider;
-
- /* Initialize the service provider */
- attest_iface = attest_provider_init(&attest_provider);
-
- attest_provider_register_serializer(&attest_provider,
- TS_RPC_ENCODING_PACKED_C, packedc_attest_provider_serializer_instance());
-
- return attest_iface;
-}
-
-struct rpc_interface *crypto_proxy_create(void)
-{
- struct rpc_interface *crypto_iface = NULL;
- struct crypto_provider *crypto_provider;
-
- if (stub_crypto_backend_init() == PSA_SUCCESS) {
-
- crypto_provider = crypto_provider_factory_create();
- crypto_iface = service_provider_get_rpc_interface(&crypto_provider->base_provider);
- }
-
- return crypto_iface;
-}
-
-struct rpc_interface *ps_proxy_create(void)
-{
- static struct mock_store ps_backend;
- static struct secure_storage_provider ps_provider;
-
- struct storage_backend *backend = mock_store_init(&ps_backend);
-
- return secure_storage_provider_init(&ps_provider, backend);
-}
-
-struct rpc_interface *its_proxy_create(void)
-{
- static struct mock_store its_backend;
- static struct secure_storage_provider its_provider;
-
- struct storage_backend *backend = mock_store_init(&its_backend);
-
- return secure_storage_provider_init(&its_provider, backend);
-}
diff --git a/deployments/se-proxy/se-proxy.cmake b/deployments/se-proxy/se-proxy.cmake
new file mode 100644
index 000000000..53bbf9514
--- /dev/null
+++ b/deployments/se-proxy/se-proxy.cmake
@@ -0,0 +1,59 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "se-proxy"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/tlv"
+ "components/rpc/common/interface"
+ "components/rpc/common/endpoint"
+ "components/service/common/include"
+ "components/service/common/serializer/protobuf"
+ "components/service/common/client"
+ "components/service/common/provider"
+ "components/service/crypto/client/psa"
+ "components/service/crypto/include"
+ "components/service/crypto/provider"
+ "components/service/crypto/provider/serializer/protobuf"
+ "components/service/crypto/provider/serializer/packed-c"
+ "components/service/crypto/provider/extension/hash"
+ "components/service/crypto/provider/extension/hash/serializer/packed-c"
+ "components/service/crypto/provider/extension/cipher"
+ "components/service/crypto/provider/extension/cipher/serializer/packed-c"
+ "components/service/crypto/provider/extension/key_derivation"
+ "components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
+ "components/service/crypto/provider/extension/mac"
+ "components/service/crypto/provider/extension/mac/serializer/packed-c"
+ "components/service/crypto/provider/extension/aead"
+ "components/service/crypto/provider/extension/aead/serializer/packed-c"
+ "components/service/crypto/factory/full"
+ "components/service/secure_storage/include"
+ "components/service/secure_storage/frontend/secure_storage_provider"
+ "components/service/attestation/include"
+ "components/service/attestation/provider"
+ "components/service/attestation/provider/serializer/packed-c"
+ "protocols/rpc/common/packed-c"
+ "protocols/service/secure_storage/packed-c"
+ "protocols/service/crypto/protobuf"
+)
+
+#-------------------------------------------------------------------------------
+# Components used from external projects
+#
+#-------------------------------------------------------------------------------
+
+# Nanopb
+include(${TS_ROOT}/external/nanopb/nanopb.cmake)
+target_link_libraries(se-proxy PRIVATE nanopb::protobuf-nanopb-static)
+protobuf_generate_all(TGT "se-proxy" NAMESPACE "protobuf" BASE_DIR "${TS_ROOT}/protocols")
+
+#################################################################
+
+target_include_directories(se-proxy PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
diff --git a/deployments/sfs-demo/opteesp/.gitignore b/deployments/sfs-demo/opteesp/.gitignore
deleted file mode 100644
index 378eac25d..000000000
--- a/deployments/sfs-demo/opteesp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-build
diff --git a/deployments/sfs-demo/opteesp/CMakeLists.txt b/deployments/sfs-demo/opteesp/CMakeLists.txt
deleted file mode 100644
index 05b338a69..000000000
--- a/deployments/sfs-demo/opteesp/CMakeLists.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
-include(../../deployment.cmake REQUIRED)
-
-#-------------------------------------------------------------------------------
-# The CMakeLists.txt for building the sfs-demo deployment for opteesp
-#
-# Used for building a demo sp that acts as a client of the secure storage
-# service, deployed in another sp.
-#-------------------------------------------------------------------------------
-include(${TS_ROOT}/environments/opteesp/env.cmake)
-project(trusted-services LANGUAGES C ASM)
-add_executable(sfs-demo)
-set(SP_UUID "01109cf8-e5ca-446f-9b55-f3cdc65110c8")
-set(TRACE_PREFIX "SFSDEMO" CACHE STRING "Trace prefix")
-
-
-# Include SP DEV KIT interface
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit REQUIRED)
-sp_dev_kit_configure_linking(TARGET sfs-demo DEFINES ARM64=1)
-target_link_libraries(sfs-demo ${SP_DEV_KIT_LIBRARIES})
-
-
-add_components(TARGET "sfs-demo"
- BASE_DIR ${TS_ROOT}
- COMPONENTS
- components/common/trace
- components/common/utils
- components/messaging/ffa/libsp
- components/rpc/common/interface
- components/rpc/common/caller
- components/rpc/ffarpc/caller/sp
- components/service/common/include
- components/service/common/client
- components/service/secure_storage/include
- components/service/secure_storage/frontend/psa/its
- components/service/secure_storage/backend/secure_storage_client
- protocols/rpc/common/packed-c
- protocols/service/secure_storage/packed-c
- environments/opteesp
-)
-
-target_sources(sfs-demo PRIVATE
- sp.c
-)
-
-target_compile_definitions(sfs-demo PRIVATE
- ARM64=1
-)
-
-target_include_directories(sfs-demo PRIVATE
- ${TS_ROOT}
- ${TS_ROOT}/components
- ${TS_ROOT}/deployments/sfs-demo/opteesp
-)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_compile_options(sfs-demo PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
- -std=c99
- )
-
- # Options for GCC that control linking
- target_link_options(sfs-demo PRIVATE
- -zmax-page-size=4096
- )
- # Options directly for LD, these are not understood by GCC
- target_link_options(sfs-demo PRIVATE
- -Wl,--as-needed
- -Wl,--sort-section=alignment
- # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
- )
-endif()
-
-compiler_generate_stripped_elf(TARGET sfs-demo NAME "${SP_UUID}.stripped.elf" RES STRIPPED_ELF)
-
-######################################## install
-if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
-endif()
-#TODO: API header, protobuf files?
-install(TARGETS sfs-demo DESTINATION ${TS_ENV}/bin)
-install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
diff --git a/deployments/sfs-demo/opteesp/optee_sp_user_defines.h b/deployments/sfs-demo/opteesp/optee_sp_user_defines.h
deleted file mode 100644
index e773055c4..000000000
--- a/deployments/sfs-demo/opteesp/optee_sp_user_defines.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_HEADER_DEFINES_H
-#define SP_HEADER_DEFINES_H
-
-/* To get UUID definition */
-#include "sp.h"
-
-#define OPTEE_SP_FLAGS 0
-
-/* Provisioned stack size */
-#define OPTEE_SP_STACK_SIZE (64 * 1024)
-
-/* Provisioned heap size */
-#define OPTEE_SP_HEAP_SIZE (32 * 1024)
-
-#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/sfs-demo/opteesp/sp.c b/deployments/sfs-demo/opteesp/sp.c
deleted file mode 100644
index 1f049ae33..000000000
--- a/deployments/sfs-demo/opteesp/sp.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "sp.h"
-#include <ffa_api.h>
-#include <components/rpc/ffarpc/caller/sp/ffarpc_caller.h>
-#include <components/service/secure_storage/frontend/psa/its/its_frontend.h>
-#include <service/secure_storage/backend/secure_storage_client/secure_storage_client.h>
-#include <psa/internal_trusted_storage.h>
-#include <sp_api.h>
-#include "sp_messaging.h"
-#include <sp_rxtx.h>
-#include <trace.h>
-#include <string.h>
-
-// #define SP_ITS_UUID_BYTES \
-// { 0xdc, 0x1e, 0xef, 0x48, 0xb1, 0x7a, 0x4c, 0xcf, \
-// 0xac, 0x8b, 0xdf, 0xcf, 0xf7, 0x71, 0x1b, 0x14, }
-
-#define SP_ITS_UUID_BYTES \
- { 0x48, 0xef, 0x1e, 0xdc, 0x7a, 0xb1, 0xcf, 0x4c, \
- 0xac, 0x8b, 0xdf, 0xcf, 0xf7, 0x71, 0x1b, 0x14, }
-
-uint16_t own_id = 0;
-static uint8_t tx_buffer[4096] __aligned(4096);
-static uint8_t rx_buffer[4096] __aligned(4096);
-static const uint8_t its_uuid[] = SP_ITS_UUID_BYTES;
-
-static const psa_storage_uid_t test_data_uid = 0x12345678;
-static const uint8_t test_data[] = {
- 0xc3, 0xe2, 0xf8, 0x1c, 0xe0, 0x87, 0x8a, 0x14, 0xbf, 0x59, 0xa3, 0xff,
- 0x96, 0x50, 0x25, 0x95, 0x76, 0xdc, 0xbe, 0xe6, 0x45, 0x45, 0x1d, 0x1b,
- 0x34, 0x6a, 0xa1, 0x1c, 0xba, 0x24, 0xa9, 0x82, 0xf1, 0x03, 0x30, 0x9b,
- 0x7d, 0xf6, 0x30, 0x88, 0xc2, 0xfb, 0xd7, 0x43, 0xfa, 0x82, 0x7c, 0x30,
- 0x49, 0x71, 0xcb, 0xe6, 0xf8, 0x18, 0xb9, 0xfc, 0x61, 0x92, 0x8c, 0x86,
- 0x01, 0x3a, 0x4a, 0xba, 0x88, 0x58, 0x63, 0x27, 0x9a, 0x47, 0xd3, 0x10,
- 0xbf, 0x80, 0x70, 0x19, 0xab, 0xc3, 0x88, 0xdb, 0xc3, 0x0c, 0x6e, 0xe5,
- 0xb1, 0xed, 0x9f, 0x47, 0xd4, 0x02, 0xa3, 0xb5, 0xb5, 0x7a, 0x20, 0x48,
- 0xd5, 0x78, 0x95, 0x7d, 0xb8, 0x33, 0xb0, 0xad, 0x4a, 0x17, 0x5a, 0xff,
- 0xd0, 0x12, 0x32, 0x84, 0x9a, 0xa3, 0x98, 0xd9, 0x26, 0x47, 0x55, 0xb7,
- 0x31, 0x96, 0x1f, 0x89, 0xd7, 0xe1, 0x01, 0x5a, 0x71, 0x6d, 0xc1, 0xe2,
- 0x26, 0x98, 0x12, 0x71, 0x4f, 0xa1, 0xdb, 0x50, 0xc4, 0xc6, 0x2f, 0xed,
- 0x5b, 0xf1, 0x52, 0x97, 0x8e, 0xdb, 0xeb, 0x56, 0x41, 0xf5, 0x9c, 0xbf,
- 0x6c, 0xe2, 0x1b, 0x14, 0x23, 0xb6, 0x1d, 0x68, 0x0b, 0x70, 0xa4, 0xc8,
- 0x70, 0x9f, 0x0a, 0x65, 0x83, 0x27, 0xd5, 0xbb, 0x4b, 0x7d, 0x55, 0x25,
- 0xe1, 0x9a, 0xaa, 0x10, 0x5c, 0x49, 0x8f, 0x0f, 0xee, 0x61, 0x49, 0x70,
- 0xee, 0x55, 0x46, 0xec, 0x8b, 0x52, 0xf6, 0x65, 0x28, 0x7f, 0x56, 0x7a,
- 0xe2, 0xb3, 0xd2, 0xbf, 0xc3, 0x0c, 0x06, 0x8e, 0x5f, 0xdc, 0xd3, 0x1f,
- 0x85, 0x74, 0x38, 0x96, 0x5e, 0x1b, 0xe5, 0xa0, 0xc0, 0xfb, 0x90, 0xb7,
- 0x14, 0x16, 0x1b, 0xbe, 0xd8, 0x5c, 0x8e, 0xcc, 0x74, 0x71, 0x8c, 0x34,
- 0xc0, 0xbc, 0x24, 0xf5, 0xb9, 0x9b, 0xa1, 0x59, 0xe8, 0x54, 0xd0, 0xe9,
- 0x01, 0xa9, 0x6e, 0x27,
-};
-static const size_t test_data_size = sizeof(test_data);
-static uint8_t check_data[256] = { 0 };
-static size_t check_data_size = 0;
-
-static void run_its_test(void)
-{
- psa_status_t its_status;
- struct psa_storage_info_t info;
-
- /* Write data */
- its_status = psa_its_set(test_data_uid, test_data_size, test_data,
- PSA_STORAGE_FLAG_NONE);
-
- if (its_status != PSA_SUCCESS) {
- EMSG("Error: %d", its_status);
- }
-
- /* Read back and compare */
- its_status = psa_its_get(test_data_uid, 0, test_data_size,
- check_data, &check_data_size);
-
- if (its_status != PSA_SUCCESS || check_data_size != test_data_size) {
- EMSG("Error: %d", its_status);
- }
-
- if(memcmp(test_data, check_data, test_data_size)) {
- EMSG("Data check failed");
- }
-
- memset(check_data, 0, test_data_size);
-
- /* Get info of entry */
- psa_its_get_info(test_data_uid, &info);
- if (its_status != PSA_SUCCESS) {
- EMSG("Error: %d", its_status);
- }
-
- /* Write data with new uid */
- its_status = psa_its_set(test_data_uid + 1, test_data_size, test_data,
- PSA_STORAGE_FLAG_NONE);
-
- if (its_status != PSA_SUCCESS) {
- EMSG("Error: %d", its_status);
- }
-
- /* Read back and compare */
- its_status = psa_its_get(test_data_uid + 1, 0, test_data_size,
- check_data, &check_data_size);
-
- if (its_status != PSA_SUCCESS || check_data_size != test_data_size) {
- EMSG("Error: %d", its_status);
- }
-
- if(memcmp(test_data, check_data, test_data_size)) {
- EMSG("Data check failed");
- }
-
- /* Delete entry */
- its_status = psa_its_remove(test_data_uid + 1);
- if (its_status != PSA_SUCCESS) {
- EMSG("Error: %d", its_status);
- }
-
- /* Check if really deleted */
- its_status = psa_its_get(test_data_uid + 1, 0, test_data_size,
- check_data, &check_data_size);
-
- if (its_status != PSA_ERROR_DOES_NOT_EXIST) {
- EMSG("Error: %d", its_status);
- }
-
- IMSG("ITS test done");
-}
-
-void __noreturn sp_main(struct ffa_init_info *init_info) {
-
- ffa_result ffa_res;
- sp_result sp_res;
- struct sp_msg req_msg = { 0 };
- struct rpc_caller *caller;
- struct ffarpc_caller ffa_caller;
- struct secure_storage_client secure_storage_client;
- struct storage_backend *storage_backend;
- uint16_t sp_ids[3];
- uint32_t sp_id_cnt = 0;
-
- /* Boot */
- (void) init_info;
- IMSG("Test SP started");
-
- sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
- if (sp_res != SP_RESULT_OK) {
- goto err;
- }
-
- ffa_res = ffa_id_get(&own_id);
- if (ffa_res != FFA_OK) {
- goto err;
- }
- IMSG("Test SP ID: 0x%x", own_id);
-
- caller = ffarpc_caller_init(&ffa_caller);
- sp_id_cnt = ffarpc_caller_discover(its_uuid, sp_ids, 3);
-
- if (sp_id_cnt == 0) {
- EMSG("Error: %d", sp_id_cnt);
- goto err;
- }
- IMSG("ITS SP ID: 0x%x", sp_ids[0]);
-
- if (ffarpc_caller_open(&ffa_caller, sp_ids[0], 0)) {
- goto err;
- }
-
- storage_backend = secure_storage_client_init(&secure_storage_client, caller);
- psa_its_frontend_init(storage_backend);
-
- /*
- * This is not thorough testing of the ITS SP!
- * Only some basic functionality checks.
- */
- run_its_test();
-
- if (ffarpc_caller_close(&ffa_caller)) {
- goto err;
- }
-
- /* End of boot phase */
- sp_msg_wait(&req_msg);
-
-err:
- EMSG("Test SP error");
- while (1) {}
-}
-
-void sp_interrupt_handler(uint32_t interrupt_id) {
- (void)interrupt_id;
-}
diff --git a/deployments/sfs-demo/opteesp/sp.h b/deployments/sfs-demo/opteesp/sp.h
deleted file mode 100644
index 2b66c1c90..000000000
--- a/deployments/sfs-demo/opteesp/sp.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_H
-#define SP_H
-
-#define OPTEE_SP_UUID \
- { 0x01109cf8, 0xe5ca, 0x446f, \
- { 0x9b, 0x55, 0xf3, 0xcd, 0xc6, 0x51, 0x10, 0xc8 } }
-
-#define SP_UUID_BYTES \
- { 0x01, 0x10, 0x9c, 0xf8, 0xe5, 0xca, 0x44, 0x6f, \
- 0x9b, 0x55, 0xf3, 0xcd, 0xc6, 0x51, 0x10, 0xc8, }
-
-#endif /* SP_H */
diff --git a/deployments/smm-gateway/common/smm_gateway.c b/deployments/smm-gateway/common/smm_gateway.c
new file mode 100644
index 000000000..f7279fa21
--- /dev/null
+++ b/deployments/smm-gateway/common/smm_gateway.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+#include <service/uefi/smm_variable/provider/smm_variable_provider.h>
+#include <service/crypto/client/psa/psa_crypto_client.h>
+#include "psa/crypto.h"
+#include <service/secure_storage/backend/secure_storage_client/secure_storage_client.h>
+#include <service/secure_storage/backend/mock_store/mock_store.h>
+#include <service_locator.h>
+
+/* Build-time default configuration */
+
+/* Default to using the Protected Storage SP */
+#ifndef SMM_GATEWAY_NV_STORE_SN
+#define SMM_GATEWAY_NV_STORE_SN "sn:ffa:751bf801-3dde-4768-a514-0f10aeed1790:0"
+#endif
+
+#if defined(UEFI_AUTH_VAR) && !defined(UEFI_INTERNAL_CRYPTO)
+/* Default to using the Crypto SP */
+#ifndef SMM_GATEWAY_CRYPTO_SN
+#define SMM_GATEWAY_CRYPTO_SN "sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0:0"
+#endif
+#endif
+
+/* Default maximum number of UEFI variables */
+#ifndef SMM_GATEWAY_MAX_UEFI_VARIABLES
+#define SMM_GATEWAY_MAX_UEFI_VARIABLES (40)
+#endif
+
+/* The smm_gateway instance - it's a singleton */
+static struct smm_gateway
+{
+ struct smm_variable_provider smm_variable_provider;
+ struct secure_storage_client nv_store_client;
+ struct mock_store volatile_store;
+ struct service_context *nv_storage_service_context;
+ struct rpc_caller_session *nv_storage_session;
+#if defined(UEFI_AUTH_VAR) && !defined(UEFI_INTERNAL_CRYPTO)
+ struct service_context *crypto_service_context;
+ struct rpc_caller_session *crypto_session;
+#endif
+
+} smm_gateway_instance;
+
+#if defined(UEFI_AUTH_VAR) && !defined(UEFI_INTERNAL_CRYPTO)
+bool create_crypto_binding(void)
+{
+ psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+
+ smm_gateway_instance.crypto_service_context = NULL;
+ smm_gateway_instance.crypto_session = NULL;
+
+ smm_gateway_instance.crypto_service_context = service_locator_query(SMM_GATEWAY_CRYPTO_SN);
+ if (!smm_gateway_instance.crypto_service_context)
+ goto err;
+
+ smm_gateway_instance.crypto_session =
+ service_context_open(smm_gateway_instance.crypto_service_context);
+ if (!smm_gateway_instance.crypto_session)
+ goto err;
+
+ /* Initialize the crypto client */
+ psa_status = psa_crypto_client_init(smm_gateway_instance.crypto_session);
+ if (psa_status != PSA_SUCCESS)
+ goto err;
+
+ psa_status = psa_crypto_init();
+ if (psa_status != PSA_SUCCESS)
+ goto err;
+
+ return true;
+
+err:
+ if (smm_gateway_instance.crypto_session != NULL)
+ {
+ service_context_close(smm_gateway_instance.crypto_service_context, smm_gateway_instance.crypto_session);
+ smm_gateway_instance.crypto_session = NULL;
+ }
+
+ if (smm_gateway_instance.crypto_service_context != NULL)
+ {
+ service_context_relinquish(smm_gateway_instance.crypto_service_context);
+ smm_gateway_instance.crypto_service_context = NULL;
+ }
+
+ return false;
+}
+#else
+#define create_crypto_binding(a) (true)
+#endif
+
+struct rpc_service_interface *smm_gateway_create(uint32_t owner_id)
+{
+ service_locator_envinit();
+
+ /* todo - add option to use configurable service location */
+ smm_gateway_instance.nv_storage_service_context =
+ service_locator_query(SMM_GATEWAY_NV_STORE_SN);
+
+ if (!smm_gateway_instance.nv_storage_service_context)
+ return NULL;
+
+ smm_gateway_instance.nv_storage_session = service_context_open(
+ smm_gateway_instance.nv_storage_service_context);
+
+ if (!smm_gateway_instance.nv_storage_session)
+ return NULL;
+
+ /* Initialize a storage client to access the remote NV store */
+ struct storage_backend *persistent_backend = secure_storage_client_init(
+ &smm_gateway_instance.nv_store_client,
+ smm_gateway_instance.nv_storage_session);
+ if (!persistent_backend)
+ return NULL;
+
+ /* Initialize the volatile storage backend */
+ struct storage_backend *volatile_backend = mock_store_init(
+ &smm_gateway_instance.volatile_store);
+ if (!volatile_backend)
+ return NULL;
+
+ /* Initialize the smm_variable service provider */
+ struct rpc_service_interface *service_iface = smm_variable_provider_init(
+ &smm_gateway_instance.smm_variable_provider,
+ owner_id,
+ SMM_GATEWAY_MAX_UEFI_VARIABLES,
+ persistent_backend,
+ volatile_backend);
+
+ if (!create_crypto_binding())
+ return NULL;
+
+ return service_iface;
+}
diff --git a/deployments/smm-gateway/smm_gateway.h b/deployments/smm-gateway/common/smm_gateway.h
index 71cadaa27..4dcb59e3e 100644
--- a/deployments/smm-gateway/smm_gateway.h
+++ b/deployments/smm-gateway/common/smm_gateway.h
@@ -7,7 +7,7 @@
#ifndef SMM_GATEWAY_H
#define SMM_GATEWAY_H
-#include <rpc/common/endpoint/rpc_interface.h>
+#include "rpc/common/endpoint/rpc_service_interface.h"
#ifdef __cplusplus
extern "C" {
@@ -25,8 +25,7 @@ extern "C" {
*
* \return An rpc_interface or NULL on failure
*/
-struct rpc_interface *smm_gateway_create(
- uint32_t owner_id);
+struct rpc_service_interface *smm_gateway_create(uint32_t owner_id);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt b/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
new file mode 100644
index 000000000..3f844e6ae
--- /dev/null
+++ b/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
@@ -0,0 +1,113 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the smm-gateway deployment for opteesp
+#
+# Provides a service provider for UEFI SMM services that are delegated to
+# other trusted service providers.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(smm-gateway)
+target_include_directories(smm-gateway PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+#-------------------------------------------------------------------------------
+# Options and variables
+#-------------------------------------------------------------------------------
+option(UEFI_AUTH_VAR "Enable variable authentication" ON)
+if (UEFI_AUTH_VAR)
+ target_compile_definitions(smm-gateway PRIVATE
+ -DUEFI_AUTH_VAR
+ )
+endif()
+
+set(SP_BIN_UUID_CANON "ed32d533-99e6-4209-9cc0-2d72cdd998a7")
+set(SP_FFA_UUID_CANON "${SP_BIN_UUID_CANON}")
+
+if (UEFI_AUTH_VAR)
+set(SP_HEAP_SIZE "64 * 1024" CACHE STRING "SP heap size in bytes")
+else()
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+endif()
+
+set(TRACE_PREFIX "SMMGW" CACHE STRING "Trace prefix")
+
+# Setting the MM communication buffer parameters
+set(MM_COMM_BUFFER_ADDRESS "0x00000008 0x81000000" CACHE STRING "Address of MM communicte buffer in 64 bit DTS format")
+set(MM_COMM_BUFFER_PAGE_COUNT "8" CACHE STRING "Size of the MM communicate buffer in 4k pages")
+
+target_include_directories(smm-gateway PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the opteesp environment.
+#
+#-------------------------------------------------------------------------------
+
+add_components(TARGET "smm-gateway"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+)
+
+include(../../env/commonsp/smm_gateway_sp.cmake REQUIRED)
+include(../../infra/psa-varstore.cmake REQUIRED)
+include(../../smm-gateway.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "smm-gateway")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(smm-gateway PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(smm-gateway PRIVATE
+ -std=c11
+ -Werror
+ )
+
+endif()
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+#TODO: api headers
+
+install(TARGETS smm-gateway
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+get_property(_PROTO_FILES TARGET smm-gateway PROPERTY PROTOBUF_FILES)
+install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME "smm-gateway"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_smm-gateway.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/smm-gateway/opteesp/default_smm-gateway.dts.in b/deployments/smm-gateway/config/default-opteesp/default_smm-gateway.dts.in
index 0ad7878ba..d74c2f3ee 100644
--- a/deployments/smm-gateway/opteesp/default_smm-gateway.dts.in
+++ b/deployments/smm-gateway/config/default-opteesp/default_smm-gateway.dts.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,7 +15,9 @@
exception-level = <1>; /* S-EL0 */
execution-state = <0>; /* AArch64 */
xlat-granule = <0>; /* 4KiB */
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
memory-regions {
compatible = "arm,ffa-manifest-memory-regions";
diff --git a/deployments/smm-gateway/config/default-opteesp/optee_sp_user_defines.h b/deployments/smm-gateway/config/default-opteesp/optee_sp_user_defines.h
new file mode 100644
index 000000000..598cbccf9
--- /dev/null
+++ b/deployments/smm-gateway/config/default-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef SP_HEADER_DEFINES_H
+#define SP_HEADER_DEFINES_H
+
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/smm-gateway/config/default-sp/CMakeLists.txt b/deployments/smm-gateway/config/default-sp/CMakeLists.txt
new file mode 100644
index 000000000..6a3f89081
--- /dev/null
+++ b/deployments/smm-gateway/config/default-sp/CMakeLists.txt
@@ -0,0 +1,112 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the smm-gateway deployment for generic sp
+# environment.
+#
+# Provides a service provider for UEFI SMM services that are delegated to
+# other trusted service providers.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/sp/env.cmake)
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type")
+project(trusted-services LANGUAGES C ASM)
+add_executable(smm-gateway)
+target_include_directories(smm-gateway PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+#-------------------------------------------------------------------------------
+# Options and variables
+#-------------------------------------------------------------------------------
+option(UEFI_AUTH_VAR "Enable variable authentication" ON)
+if (UEFI_AUTH_VAR)
+ target_compile_definitions(smm-gateway PRIVATE
+ -DUEFI_AUTH_VAR
+ )
+endif()
+
+set(SP_NAME "smm-gateway")
+set(SP_BIN_UUID_CANON "ed32d533-99e6-4209-9cc0-2d72cdd998a7")
+set(SP_FFA_UUID_CANON "${SP_BIN_UUID_CANON}")
+set(TRACE_PREFIX "SMMGW" CACHE STRING "Trace prefix")
+set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
+
+if (UEFI_AUTH_VAR)
+set(SP_HEAP_SIZE "64 * 1024" CACHE STRING "Heap size")
+else()
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+endif()
+
+# Setting the MM communication buffer parameters
+set(MM_COMM_BUFFER_ADDRESS "0x00000008 0x81000000" CACHE STRING "Address of MM communicte buffer in 64 bit DTS format")
+set(MM_COMM_BUFFER_PAGE_COUNT "8" CACHE STRING "Size of the MM communicate buffer in 4k pages")
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the opteesp environment.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "smm-gateway"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ environments/sp
+)
+
+include(../../env/commonsp/smm_gateway_sp.cmake REQUIRED)
+include(../../infra/psa-varstore.cmake REQUIRED)
+include(../../smm-gateway.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "smm-gateway")
+
+#-------------------------------------------------------------------------------
+# Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(smm-gateway PRIVATE
+ ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(smm-gateway PRIVATE
+ -std=c11
+ -Werror
+ )
+
+endif()
+
+compiler_generate_binary_output(TARGET smm-gateway NAME "${SP_BIN_UUID_CANON}.bin" SP_BINARY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SP_BIN_UUID_CANON}.bin DESTINATION ${TS_ENV}/bin)
+
+include(${TS_ROOT}/tools/cmake/common/ExportMemoryRegionsToManifest.cmake REQUIRED)
+export_memory_regions_to_manifest(TARGET smm-gateway NAME "${SP_BIN_UUID_CANON}_memory_regions.dtsi" RES EXPORT_MEMORY_REGIONS_DTSI)
+
+#-------------------------------------------------------------------------------
+# Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS smm-gateway
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake REQUIRED)
+export_sp(
+ SP_FFA_UUID_CANON ${SP_FFA_UUID_CANON}
+ SP_BIN_UUID_CANON ${SP_BIN_UUID_CANON}
+ SP_NAME ${SP_NAME}
+ DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_${SP_NAME}.dts.in
+ DTS_MEM_REGIONS ${SP_BIN_UUID_CANON}_memory_regions.dtsi
+ JSON_IN ${TS_ROOT}/environments/sp/sp_pkg.json.in
+)
diff --git a/deployments/smm-gateway/config/default-sp/default_smm-gateway.dts.in b/deployments/smm-gateway/config/default-sp/default_smm-gateway.dts.in
new file mode 100644
index 000000000..9b8988eb1
--- /dev/null
+++ b/deployments/smm-gateway/config/default-sp/default_smm-gateway.dts.in
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ description = "SMM Gateway";
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AArch64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ #include "@EXPORT_DTS_MEM_REGIONS@"
+
+ mm-comm-buffer {
+ base-address = <@MM_COMM_BUFFER_ADDRESS@>;
+ pages-count = <@MM_COMM_BUFFER_PAGE_COUNT@>;
+ attributes = <0xb>; /* ns access-read-write */
+ };
+ };
+};
diff --git a/deployments/smm-gateway/linux-pc/CMakeLists.txt b/deployments/smm-gateway/config/linux-pc/CMakeLists.txt
index 09a1333ac..aaec898db 100644
--- a/deployments/smm-gateway/linux-pc/CMakeLists.txt
+++ b/deployments/smm-gateway/config/linux-pc/CMakeLists.txt
@@ -1,11 +1,11 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
-include(../../deployment.cmake REQUIRED)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+include(../../../deployment.cmake REQUIRED)
project(smm-gateway-unit-tests LANGUAGES CXX C)
@@ -52,4 +52,4 @@ endif()
include(${TS_ROOT}/components/rpc/common/tests.cmake)
include(${TS_ROOT}/components/rpc/mm_communicate/endpoint/sp/tests.cmake)
-include(${TS_ROOT}/components/service/smm_variable/frontend/mm_communicate/tests.cmake)
+include(${TS_ROOT}/components/service/uefi/smm_variable/frontend/mm_communicate/tests.cmake)
diff --git a/deployments/smm-gateway/env/commonsp/smm_gateway_sp.c b/deployments/smm-gateway/env/commonsp/smm_gateway_sp.c
new file mode 100644
index 000000000..c87e73e93
--- /dev/null
+++ b/deployments/smm-gateway/env/commonsp/smm_gateway_sp.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "deployments/smm-gateway/common/smm_gateway.h"
+#include "config/ramstore/config_ramstore.h"
+#include "config/interface/config_store.h"
+#include "config/loader/sp/sp_config_loader.h"
+#include "components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h"
+#include "components/service/uefi/smm_variable/frontend/mm_communicate/smm_variable_mm_service.h"
+#include "platform/interface/memory_region.h"
+#include "protocols/common/mm/mm_smc.h"
+#include "ffa_api.h"
+#include "sp_api.h"
+#include "sp_discovery.h"
+#include "sp_messaging.h"
+#include "sp_rxtx.h"
+#include "trace.h"
+
+#define CONFIG_NAME_MM_COMM_BUFFER_REGION "mm-comm-buffer"
+
+static bool sp_init(uint16_t *own_sp_id);
+
+void __noreturn sp_main(union ffa_boot_info *boot_info)
+{
+ struct memory_region mm_comm_buffer_region = { 0 };
+ struct rpc_service_interface *gateway_iface = NULL;
+ struct smm_variable_mm_service smm_var_service = { 0 };
+ struct mm_service_interface *smm_var_service_interface = NULL;
+ struct mm_communicate_ep mm_communicate_call_ep = { 0 };
+ struct ffa_direct_msg req_msg = { 0 };
+ struct ffa_direct_msg resp_msg = { 0 };
+ uint16_t own_id = 0;
+ ffa_result result = FFA_DENIED;
+
+ static const EFI_GUID smm_variable_guid = SMM_VARIABLE_GUID;
+
+ /* Boot phase */
+ if (!sp_init(&own_id)) {
+ EMSG("Failed to init SP");
+ goto fatal_error;
+ }
+
+ /* Load any dynamic configuration */
+ config_ramstore_init();
+
+ if (!sp_config_load(boot_info)) {
+ EMSG("Failed to load SP config");
+ goto fatal_error;
+ }
+
+ if (!config_store_query(CONFIG_CLASSIFIER_MEMORY_REGION, CONFIG_NAME_MM_COMM_BUFFER_REGION,
+ 0, &mm_comm_buffer_region, sizeof(mm_comm_buffer_region))) {
+ EMSG(CONFIG_NAME_MM_COMM_BUFFER_REGION " is not set in SP configuration");
+ goto fatal_error;
+ }
+
+ /* Initialize service layer and associate with RPC endpoint */
+ gateway_iface = smm_gateway_create(own_id);
+ if (!gateway_iface) {
+ EMSG("Failed to create SMM gateway");
+ goto fatal_error;
+ }
+
+ /* Initialize SMM variable MM service */
+ smm_var_service_interface = smm_variable_mm_service_init(&smm_var_service, gateway_iface);
+ if (!smm_var_service_interface) {
+ EMSG("Failed to init SMM variable MM service");
+ goto fatal_error;
+ }
+
+ /* Initialize MM communication layer */
+ if (!mm_communicate_call_ep_init(&mm_communicate_call_ep,
+ (void *)mm_comm_buffer_region.base_addr,
+ mm_comm_buffer_region.region_size)) {
+ EMSG("Failed to init MM communicate call EP");
+ goto fatal_error;
+ }
+
+ /* Attach SMM variable service to MM communication layer */
+ mm_communicate_call_ep_attach_service(&mm_communicate_call_ep, &smm_variable_guid,
+ smm_var_service_interface);
+
+ /* End of boot phase */
+ result = ffa_msg_wait(&req_msg);
+ if (result != FFA_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+
+ while (1) {
+ if (FFA_IS_32_BIT_FUNC(req_msg.function_id)) {
+ EMSG("MM communicate over 32 bit FF-A messages is not supported");
+ ffa_msg_send_direct_resp_32(req_msg.destination_id, req_msg.source_id,
+ MM_RETURN_CODE_NOT_SUPPORTED, 0, 0, 0, 0,
+ &req_msg);
+ continue;
+ }
+
+ mm_communicate_call_ep_receive(&mm_communicate_call_ep, &req_msg, &resp_msg);
+
+ result = ffa_msg_send_direct_resp_64(req_msg.destination_id,
+ req_msg.source_id, resp_msg.args.args64[0],
+ resp_msg.args.args64[1], resp_msg.args.args64[2],
+ resp_msg.args.args64[3], resp_msg.args.args64[4],
+ &req_msg);
+ if (result != FFA_OK) {
+ EMSG("Failed to send direct response %d", result);
+ result = ffa_msg_wait(&req_msg);
+ if (result != FFA_OK) {
+ EMSG("Failed to send message wait %d", result);
+ goto fatal_error;
+ }
+ }
+ }
+
+fatal_error:
+ /* SP is not viable */
+ EMSG("SMM gateway SP error");
+ while (1) {}
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+}
+
+static bool sp_init(uint16_t *own_id)
+{
+ sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
+ static uint8_t tx_buffer[4096] __aligned(4096);
+ static uint8_t rx_buffer[4096] __aligned(4096);
+
+ sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to map RXTX buffers: %d", sp_res);
+ return false;
+ }
+
+ sp_res = sp_discovery_own_id_get(own_id);
+ if (sp_res != SP_RESULT_OK) {
+ EMSG("Failed to query own ID: %d", sp_res);
+ return false;
+ }
+
+ return true;
+}
diff --git a/deployments/smm-gateway/env/commonsp/smm_gateway_sp.cmake b/deployments/smm-gateway/env/commonsp/smm_gateway_sp.cmake
new file mode 100644
index 000000000..0dc754986
--- /dev/null
+++ b/deployments/smm-gateway/env/commonsp/smm_gateway_sp.cmake
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Includes components needed for deploying the smm-gateway within a secure
+# partition.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Common components for smm-gateway sp deployments
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "smm-gateway"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "components/rpc/common/endpoint"
+ "components/rpc/ts_rpc/common"
+ "components/rpc/ts_rpc/caller/sp"
+ "components/rpc/mm_communicate/endpoint/sp"
+ "components/service/locator/sp"
+ "components/service/locator/sp/ffa"
+ "components/service/uefi/smm_variable/frontend/mm_communicate"
+)
+
+target_sources(smm-gateway PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/smm_gateway_sp.c
+ ${TS_ROOT}/deployments/smm-gateway/common/smm_gateway.c
+)
diff --git a/deployments/smm-gateway/env/commonsp/smm_gateway_sp.h b/deployments/smm-gateway/env/commonsp/smm_gateway_sp.h
new file mode 100644
index 000000000..6f231352e
--- /dev/null
+++ b/deployments/smm-gateway/env/commonsp/smm_gateway_sp.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMM_GATEWAY_SP_H
+#define SMM_GATEWAY_SP_H
+
+#endif /* SMM_GATEWAY_SP_H */
diff --git a/deployments/smm-gateway/infra/psa-varstore.cmake b/deployments/smm-gateway/infra/psa-varstore.cmake
new file mode 100644
index 000000000..2c3317866
--- /dev/null
+++ b/deployments/smm-gateway/infra/psa-varstore.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# An infrastrucure to support the smm-gateway. Uses PSA storage for persistent
+# storage of NV UEFI variables.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "smm-gateway"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/rpc/common/caller"
+ "components/service/common/client"
+ "components/service/locator"
+ "components/service/locator/interface"
+ "components/service/secure_storage/backend/secure_storage_client"
+ "protocols/service/secure_storage/packed-c"
+)
diff --git a/deployments/smm-gateway/opteesp/CMakeLists.txt b/deployments/smm-gateway/opteesp/CMakeLists.txt
deleted file mode 100644
index c3f267499..000000000
--- a/deployments/smm-gateway/opteesp/CMakeLists.txt
+++ /dev/null
@@ -1,136 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
-
-# Set default platform.
-set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
-include(../../deployment.cmake REQUIRED)
-
-#-------------------------------------------------------------------------------
-# The CMakeLists.txt for building the smm-gateway deployment for opteesp
-#
-# Provides a service provider for UEFI SMM services that are delegated to
-# other trusted service providers.
-#-------------------------------------------------------------------------------
-include(${TS_ROOT}/environments/opteesp/env.cmake)
-project(trusted-services LANGUAGES C ASM)
-add_executable(smm-gateway)
-target_include_directories(smm-gateway PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
-set(SP_UUID "ed32d533-99e6-4209-9cc0-2d72cdd998a7")
-
-# Setting the MM communication buffer parameters
-set(MM_COMM_BUFFER_ADDRESS "0x00000008 0x81000000" CACHE STRING "Address of MM communicte buffer in 64 bit DTS format")
-set(MM_COMM_BUFFER_PAGE_COUNT "8" CACHE STRING "Size of the MM communicate buffer in 4k pages")
-
-# Include SP DEV KIT interface
-set(SP_DEV_KIT_INC_DIR ${CMAKE_CURRENT_LIST_DIR})
-list(APPEND CMAKE_MODULE_PATH "${TS_ROOT}/external/Spdevkit")
-find_package(Spdevkit REQUIRED)
-sp_dev_kit_configure_linking(TARGET smm-gateway DEFINES ARM64=1)
-target_link_libraries(smm-gateway PRIVATE ${SP_DEV_KIT_LIBRARIES})
-
-#-------------------------------------------------------------------------------
-# Components that are specific to deployment in the opteesp environment.
-#
-#-------------------------------------------------------------------------------
-add_components(TARGET "smm-gateway"
- BASE_DIR ${TS_ROOT}
- COMPONENTS
- "components/common/trace"
- "components/common/utils"
- "components/common/uuid"
- "components/config/ramstore"
- "components/config/loader/sp"
- "components/messaging/ffa/libsp"
- "components/rpc/ffarpc/endpoint"
- "components/rpc/ffarpc/caller/sp"
- "components/rpc/mm_communicate/endpoint/sp"
- "components/rpc/common/caller"
- "components/rpc/common/interface"
- "components/service/common/include"
- "components/service/common/client"
- "components/service/common/provider"
- "components/service/locator"
- "components/service/locator/interface"
- "components/service/locator/sp"
- "components/service/locator/sp/ffa"
- "components/service/smm_variable/backend"
- "components/service/smm_variable/frontend/mm_communicate"
- "components/service/smm_variable/provider"
- "components/service/secure_storage/include"
- "components/service/secure_storage/backend/secure_storage_client"
- "components/service/secure_storage/backend/mock_store"
- "protocols/rpc/common/packed-c"
- "protocols/service/secure_storage/packed-c"
- "environments/opteesp"
-)
-
-target_sources(smm-gateway PRIVATE
- smm_gateway_sp.c
- ../smm_gateway.c
-)
-
-#-------------------------------------------------------------------------------
-# Set target platform to provide drivers needed by the deployment
-#
-#-------------------------------------------------------------------------------
-add_platform(TARGET "smm-gateway")
-
-#################################################################
-
-target_compile_definitions(smm-gateway PRIVATE
- ARM64=1
-)
-
-target_include_directories(smm-gateway PRIVATE
- ${TS_ROOT}
- ${TS_ROOT}/components
- ${TS_ROOT}/deployments/smm-gateway/opteesp
-)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_compile_options(smm-gateway PRIVATE
- -fdiagnostics-show-option
- -gdwarf-2
- -mstrict-align
- -O0
- -std=c99
- )
-
- # Options for GCC that control linking
- target_link_options(smm-gateway PRIVATE
- -zmax-page-size=4096
- )
- # Options directly for LD, these are not understood by GCC
- target_link_options(smm-gateway PRIVATE
- -Wl,--as-needed
- -Wl,--sort-section=alignment
- # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
- )
-endif()
-
-compiler_generate_stripped_elf(TARGET smm-gateway NAME "${SP_UUID}.stripped.elf" RES STRIPPED_ELF)
-
-######################################## install
-if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
-endif()
-#TODO: api headers
-
-install(TARGETS smm-gateway
- PUBLIC_HEADER DESTINATION ${TS_ENV}/include
- RUNTIME DESTINATION ${TS_ENV}/bin
- )
-install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
-
-get_property(_PROTO_FILES TARGET smm-gateway PROPERTY PROTOBUF_FILES)
-install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
-
-
-set(EXPORT_SP_NAME "smm-gateway")
-set(EXPORT_SP_UUID ${SP_UUID})
-include(${TS_ROOT}/environments/opteesp/ExportSp.cmake)
diff --git a/deployments/smm-gateway/opteesp/optee_sp_user_defines.h b/deployments/smm-gateway/opteesp/optee_sp_user_defines.h
deleted file mode 100644
index edcd46958..000000000
--- a/deployments/smm-gateway/opteesp/optee_sp_user_defines.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SP_HEADER_DEFINES_H
-#define SP_HEADER_DEFINES_H
-
-/* To get UUID definition */
-#include "smm_gateway_sp.h"
-
-#define OPTEE_SP_UUID SMM_GATEWAY_UUID
-#define OPTEE_SP_FLAGS 0
-
-/* Provisioned stack size */
-#define OPTEE_SP_STACK_SIZE (64 * 1024)
-
-/* Provisioned heap size */
-#define OPTEE_SP_HEAP_SIZE (32 * 1024)
-
-#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/smm-gateway/opteesp/smm_gateway_sp.c b/deployments/smm-gateway/opteesp/smm_gateway_sp.c
deleted file mode 100644
index 6f138850b..000000000
--- a/deployments/smm-gateway/opteesp/smm_gateway_sp.c
+++ /dev/null
@@ -1,108 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#include <rpc/ffarpc/endpoint/ffarpc_call_ep.h>
-#include <deployments/smm-gateway/smm_gateway.h>
-#include <config/ramstore/config_ramstore.h>
-#include "config/interface/config_store.h"
-#include <config/loader/sp/sp_config_loader.h>
-#include "components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h"
-#include "components/service/smm_variable/frontend/mm_communicate/smm_variable_mm_service.h"
-#include "platform/interface/memory_region.h"
-#include <ffa_api.h>
-#include <sp_api.h>
-#include <sp_messaging.h>
-#include <sp_rxtx.h>
-#include <trace.h>
-
-#define CONFIG_NAME_MM_COMM_BUFFER_REGION "mm-comm-buffer"
-
-uint16_t own_id = 0; /* !!Needs refactoring as parameter to ffarpc_caller_init */
-
-static int sp_init(uint16_t *own_sp_id);
-
-void __noreturn sp_main(struct ffa_init_info *init_info)
-{
- struct memory_region mm_comm_buffer_region = { 0 };
- struct rpc_interface *gateway_iface = NULL;
- struct smm_variable_mm_service smm_var_service = { 0 };
- struct mm_service_interface *smm_var_service_interface = NULL;
- struct mm_communicate_ep mm_communicate_call_ep = { 0 };
- struct ffa_direct_msg req_msg = { 0 };
- struct ffa_direct_msg resp_msg = { 0 };
-
- static const EFI_GUID smm_variable_guid = SMM_VARIABLE_GUID;
-
- /* Boot phase */
- if (sp_init(&own_id) != 0) goto fatal_error;
-
- /* Load any dynamic configuration */
- config_ramstore_init();
- sp_config_load(init_info);
-
- if (!config_store_query(CONFIG_CLASSIFIER_MEMORY_REGION, CONFIG_NAME_MM_COMM_BUFFER_REGION,
- 0, &mm_comm_buffer_region, sizeof(mm_comm_buffer_region))) {
- EMSG(CONFIG_NAME_MM_COMM_BUFFER_REGION " is not set in SP configuration");
- goto fatal_error;
- }
-
- /* Initialize service layer and associate with RPC endpoint */
- gateway_iface = smm_gateway_create(own_id);
-
- /* Initialize SMM variable MM service */
- smm_var_service_interface = smm_variable_mm_service_init(&smm_var_service, gateway_iface);
-
- /* Initialize MM communication layer */
- if (!mm_communicate_call_ep_init(&mm_communicate_call_ep,
- (void *)mm_comm_buffer_region.base_addr,
- mm_comm_buffer_region.region_size))
- goto fatal_error;
-
- /* Attach SMM variable service to MM communication layer */
- mm_communicate_call_ep_attach_service(&mm_communicate_call_ep, &smm_variable_guid,
- smm_var_service_interface);
-
- /* End of boot phase */
- ffa_msg_wait(&req_msg);
-
- while (1) {
- mm_communicate_call_ep_receive(&mm_communicate_call_ep, &req_msg, &resp_msg);
-
- ffa_msg_send_direct_resp(req_msg.destination_id,
- req_msg.source_id, resp_msg.args[0],
- resp_msg.args[1], resp_msg.args[2],
- resp_msg.args[3], resp_msg.args[4],
- &req_msg);
- }
-
-fatal_error:
- /* SP is not viable */
- EMSG("SMM gateway SP error");
- while (1) {}
-}
-
-void sp_interrupt_handler(uint32_t interrupt_id)
-{
- (void)interrupt_id;
-}
-
-static int sp_init(uint16_t *own_sp_id)
-{
- int status = -1;
- ffa_result ffa_res;
- sp_result sp_res;
- static uint8_t tx_buffer[4096] __aligned(4096);
- static uint8_t rx_buffer[4096] __aligned(4096);
-
- sp_res = sp_rxtx_buffer_map(tx_buffer, rx_buffer, sizeof(rx_buffer));
- if (sp_res == SP_RESULT_OK) {
- ffa_res = ffa_id_get(own_sp_id);
- if (ffa_res == FFA_OK) {
- status = 0;
- }
- }
-
- return status;
-}
diff --git a/deployments/smm-gateway/opteesp/smm_gateway_sp.h b/deployments/smm-gateway/opteesp/smm_gateway_sp.h
deleted file mode 100644
index dd6c4136d..000000000
--- a/deployments/smm-gateway/opteesp/smm_gateway_sp.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SMM_GATEWAY_SP_H
-#define SMM_GATEWAY_SP_H
-
-#define SMM_GATEWAY_UUID \
- {0xed32d533, 0x99e6, 0x4209, \
- { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 }}
-
-#define SMM_GATEWAY_UUID_BYTES \
- {0xed, 0x32, 0xd5, 0x33, 0x99, 0xe6, 0x42, 0x09, \
- 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7}
-
-#endif /* SMM_GATEWAY_SP_H */
diff --git a/deployments/smm-gateway/smm-gateway.cmake b/deployments/smm-gateway/smm-gateway.cmake
new file mode 100644
index 000000000..e5ee03b60
--- /dev/null
+++ b/deployments/smm-gateway/smm-gateway.cmake
@@ -0,0 +1,61 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+option(UEFI_INTERNAL_CRYPTO "Use internal mbedtls instance" OFF)
+
+if (UEFI_AUTH_VAR)
+
+# If enabled an internal mbedtls instance will be used instead of the crypto SP
+if (UEFI_INTERNAL_CRYPTO)
+set(MBEDTLS_USER_CONFIG_FILE "${TS_ROOT}/external/MbedTLS/config/x509_only.h"
+ CACHE STRING "Configuration file for Mbed TLS" FORCE)
+include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
+target_link_libraries(smm-gateway PRIVATE MbedTLS::mbedcrypto)
+target_link_libraries(smm-gateway PRIVATE MbedTLS::mbedx509)
+
+target_compile_definitions(smm-gateway PRIVATE
+ -DUEFI_INTERNAL_CRYPTO
+)
+
+add_components(TARGET "smm-gateway"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/service/uefi/smm_variable/backend/direct"
+)
+
+else()
+add_components(TARGET "smm-gateway"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/tlv"
+ "components/service/crypto/include"
+ "components/service/crypto/client/psa"
+)
+endif()
+
+endif()
+
+add_components(TARGET "smm-gateway"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/trace"
+ "components/common/utils"
+ "components/common/uuid"
+ "components/rpc/common/interface"
+ "components/service/common/include"
+ "components/service/common/provider"
+ "components/service/uefi/smm_variable/backend"
+ "components/service/uefi/smm_variable/provider"
+ "components/service/secure_storage/include"
+ "components/service/secure_storage/backend/mock_store"
+ "protocols/rpc/common/packed-c"
+)
+
+target_include_directories(smm-gateway PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
diff --git a/deployments/smm-gateway/smm_gateway.c b/deployments/smm-gateway/smm_gateway.c
deleted file mode 100644
index 4884a040e..000000000
--- a/deployments/smm-gateway/smm_gateway.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-#include <protocols/rpc/common/packed-c/encoding.h>
-#include <service/smm_variable/provider/smm_variable_provider.h>
-#include <service/secure_storage/backend/secure_storage_client/secure_storage_client.h>
-#include <service/secure_storage/backend/mock_store/mock_store.h>
-#include <service_locator.h>
-
-/* Build-time default configuration */
-
-/* Default to using the Protected Storage SP */
-#ifndef SMM_GATEWAY_NV_STORE_SN
-#define SMM_GATEWAY_NV_STORE_SN "sn:ffa:751bf801-3dde-4768-a514-0f10aeed1790:0"
-#endif
-
-/* Default maximum number of UEFI variables */
-#ifndef SMM_GATEWAY_MAX_UEFI_VARIABLES
-#define SMM_GATEWAY_MAX_UEFI_VARIABLES (40)
-#endif
-
-/* The smm_gateway instance - it's a singleton */
-static struct smm_gateway
-{
- struct smm_variable_provider smm_variable_provider;
- struct secure_storage_client nv_store_client;
- struct mock_store volatile_store;
- struct service_context *nv_storage_service_context;
- rpc_session_handle nv_storage_session_handle;
-
-} smm_gateway_instance;
-
-
-static struct rpc_caller *locate_nv_store(void)
-{
- int status = 0;
- struct rpc_caller *caller = NULL;
-
- /* todo - add option to use configurable service location */
- smm_gateway_instance.nv_storage_service_context =
- service_locator_query(SMM_GATEWAY_NV_STORE_SN, &status);
-
- if (smm_gateway_instance.nv_storage_service_context) {
-
- smm_gateway_instance.nv_storage_session_handle = service_context_open(
- smm_gateway_instance.nv_storage_service_context,
- TS_RPC_ENCODING_PACKED_C,
- &caller);
- }
-
- return caller;
-}
-
-struct rpc_interface *smm_gateway_create(uint32_t owner_id)
-{
- service_locator_init();
-
- /* Initialize a storage client to access the remote NV store */
- struct rpc_caller *nv_store_caller = locate_nv_store();
- struct storage_backend *persistent_backend = secure_storage_client_init(
- &smm_gateway_instance.nv_store_client,
- nv_store_caller);
-
- /* Initialize the volatile storage backend */
- struct storage_backend *volatile_backend = mock_store_init(
- &smm_gateway_instance.volatile_store);
-
- /* Initialize the smm_variable service provider */
- struct rpc_interface *service_iface = smm_variable_provider_init(
- &smm_gateway_instance.smm_variable_provider,
- owner_id,
- SMM_GATEWAY_MAX_UEFI_VARIABLES,
- persistent_backend,
- volatile_backend);
-
- return service_iface;
-}
diff --git a/deployments/spm-test1/opteesp/CMakeLists.txt b/deployments/spm-test1/opteesp/CMakeLists.txt
new file mode 100644
index 000000000..b8fcdb5b1
--- /dev/null
+++ b/deployments/spm-test1/opteesp/CMakeLists.txt
@@ -0,0 +1,38 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../deployment.cmake REQUIRED)
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+
+project(trusted-services LANGUAGES C ASM)
+add_executable(spm-test1)
+
+set(SP_BIN_UUID_CANON "5c9edbc3-7b3a-4367-9f83-7c191ae86a37")
+set(SP_FFA_UUID_CANON "${SP_BIN_UUID_CANON}")
+set(SP_FFA_UUID_CANON "5c9edbc3-7b3a-4367-9f83-7c191ae86a37")
+set(SP_NUMBER 1)
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "SPM-TEST${SP_NUMBER}" CACHE STRING "Trace prefix")
+
+#-------------------------------------------------------------------------------
+# Components that are spm-test specific to deployment in the opteesp
+# environment.
+#-------------------------------------------------------------------------------
+add_components(TARGET "spm-test${SP_NUMBER}"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+)
+
+include(${TS_ROOT}/components/service/spm_test/spm_test.cmake)
diff --git a/deployments/spm-test1/opteesp/default_spm_test1.dts.in b/deployments/spm-test1/opteesp/default_spm_test1.dts.in
new file mode 100644
index 000000000..969bdc85a
--- /dev/null
+++ b/deployments/spm-test1/opteesp/default_spm_test1.dts.in
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+
+ /* Properties */
+ description = "SPMC test SP1";
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+ memory-regions {
+ compatible = "arm,ffa-manifest-memory-regions";
+
+ test-region {
+ /* Armv8 A Foundation Platform values */
+ base-address = <0x00000000 0x6248000>;
+ pages-count = <1>;
+ attributes = <0x3>; /* read-write */
+ };
+ };
+};
diff --git a/deployments/spm-test2/opteesp/CMakeLists.txt b/deployments/spm-test2/opteesp/CMakeLists.txt
new file mode 100644
index 000000000..7531cfb0f
--- /dev/null
+++ b/deployments/spm-test2/opteesp/CMakeLists.txt
@@ -0,0 +1,38 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../deployment.cmake REQUIRED)
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+
+project(trusted-services LANGUAGES C ASM)
+add_executable(spm-test2)
+
+set(SP_BIN_UUID_CANON "7817164c-c40c-4d1a-867a-9bb2278cf41a")
+set(SP_FFA_UUID_CANON "${SP_BIN_UUID_CANON}")
+set(SP_FFA_UUID_CANON "7817164c-c40c-4d1a-867a-9bb2278cf41a")
+set(SP_NUMBER 2)
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "SPM-TEST${SP_NUMBER}" CACHE STRING "Trace prefix")
+
+#-------------------------------------------------------------------------------
+# Components that are spm-test specific to deployment in the opteesp
+# environment.
+#-------------------------------------------------------------------------------
+add_components(TARGET "spm-test${SP_NUMBER}"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+)
+
+include(${TS_ROOT}/components/service/spm_test/spm_test.cmake)
diff --git a/deployments/spm-test2/opteesp/default_spm_test2.dts.in b/deployments/spm-test2/opteesp/default_spm_test2.dts.in
new file mode 100644
index 000000000..f75bd9e7e
--- /dev/null
+++ b/deployments/spm-test2/opteesp/default_spm_test2.dts.in
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+
+ /* Properties */
+ description = "SPMC test SP2";
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/spm-test3/opteesp/CMakeLists.txt b/deployments/spm-test3/opteesp/CMakeLists.txt
new file mode 100644
index 000000000..e97877f85
--- /dev/null
+++ b/deployments/spm-test3/opteesp/CMakeLists.txt
@@ -0,0 +1,38 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../deployment.cmake REQUIRED)
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+
+project(trusted-services LANGUAGES C ASM)
+add_executable(spm-test3)
+
+set(SP_BIN_UUID_CANON "23eb0100-e32a-4497-9052-2f11e584afa6")
+set(SP_FFA_UUID_CANON "${SP_BIN_UUID_CANON}")
+set(SP_FFA_UUID_CANON "23eb0100-e32a-4497-9052-2f11e584afa6")
+set(SP_NUMBER 3)
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "SPM-TEST${SP_NUMBER}" CACHE STRING "Trace prefix")
+
+#-------------------------------------------------------------------------------
+# Components that are spm-test specific to deployment in the opteesp
+# environment.
+#-------------------------------------------------------------------------------
+add_components(TARGET "spm-test${SP_NUMBER}"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+)
+
+include(${TS_ROOT}/components/service/spm_test/spm_test.cmake)
diff --git a/deployments/spm-test3/opteesp/default_spm_test3.dts.in b/deployments/spm-test3/opteesp/default_spm_test3.dts.in
new file mode 100644
index 000000000..c3c768fb5
--- /dev/null
+++ b/deployments/spm-test3/opteesp/default_spm_test3.dts.in
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+
+ /* Properties */
+ description = "SPMC test SP3";
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/spm-test4/opteesp/CMakeLists.txt b/deployments/spm-test4/opteesp/CMakeLists.txt
new file mode 100644
index 000000000..c51350625
--- /dev/null
+++ b/deployments/spm-test4/opteesp/CMakeLists.txt
@@ -0,0 +1,38 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../deployment.cmake REQUIRED)
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+
+project(trusted-services LANGUAGES C ASM)
+add_executable(spm-test4)
+
+set(SP_BIN_UUID_CANON "423762ed-7772-406f-99d8-0c27da0abbf8")
+set(SP_FFA_UUID_CANON "${SP_BIN_UUID_CANON}")
+set(SP_FFA_UUID_CANON "23eb0100-e32a-4497-9052-2f11e584afa6")
+set(SP_NUMBER 4)
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "SPM-TEST${SP_NUMBER}" CACHE STRING "Trace prefix")
+
+#-------------------------------------------------------------------------------
+# Components that are spm-test specific to deployment in the opteesp
+# environment.
+#-------------------------------------------------------------------------------
+add_components(TARGET "spm-test${SP_NUMBER}"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/opteesp"
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/ramstore"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+)
+
+include(${TS_ROOT}/components/service/spm_test/spm_test.cmake)
diff --git a/deployments/spm-test4/opteesp/default_spm_test4.dts.in b/deployments/spm-test4/opteesp/default_spm_test4.dts.in
new file mode 100644
index 000000000..fffc31f45
--- /dev/null
+++ b/deployments/spm-test4/opteesp/default_spm_test4.dts.in
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+
+ /* Properties */
+ description = "SPMC test SP4";
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ ns-interrupts-action = <2>; /* Non-secure interrupts are signaled */
+ elf-format = <1>;
+};
diff --git a/deployments/ts-demo/arm-linux/CMakeLists.txt b/deployments/ts-demo/arm-linux/CMakeLists.txt
index 8b2fcf431..db59599d5 100644
--- a/deployments/ts-demo/arm-linux/CMakeLists.txt
+++ b/deployments/ts-demo/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
@@ -29,5 +29,4 @@ include(../ts-demo.cmake REQUIRED)
# Define library options and dependencies.
#
#-------------------------------------------------------------------------------
-env_set_link_options(TGT ts-demo)
target_link_libraries(ts-demo PRIVATE stdc++ gcc m)
diff --git a/deployments/ts-demo/linux-pc/CMakeLists.txt b/deployments/ts-demo/linux-pc/CMakeLists.txt
index 4d49adc29..474ab6cdb 100644
--- a/deployments/ts-demo/linux-pc/CMakeLists.txt
+++ b/deployments/ts-demo/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
diff --git a/deployments/ts-demo/ts-demo.cmake b/deployments/ts-demo/ts-demo.cmake
index 3e7cca083..0769df9ba 100644
--- a/deployments/ts-demo/ts-demo.cmake
+++ b/deployments/ts-demo/ts-demo.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -13,11 +13,11 @@
#-------------------------------------------------------------------------------
# Use libts for locating and accessing services. An appropriate version of
-# libts will be imported for the enviroment in which service tests are
+# libts will be imported for the environment in which service tests are
# deployed.
#-------------------------------------------------------------------------------
include(${TS_ROOT}/deployments/libts/libts-import.cmake)
-target_link_libraries(ts-demo PRIVATE libts)
+target_link_libraries(ts-demo PRIVATE libts::ts)
#-------------------------------------------------------------------------------
# Common main for all deployments
@@ -28,7 +28,7 @@ target_sources(ts-demo PRIVATE
)
#-------------------------------------------------------------------------------
-# Components that are common accross all deployments
+# Components that are common across all deployments
#
#-------------------------------------------------------------------------------
add_components(
@@ -39,7 +39,6 @@ add_components(
"components/common/tlv"
"components/service/common/include"
"components/service/common/client"
- "components/service/discovery/client"
"components/service/crypto/client/cpp"
"components/service/crypto/client/cpp/protocol/packed-c"
"protocols/service/crypto/packed-c"
@@ -50,9 +49,11 @@ add_components(
#
#-------------------------------------------------------------------------------
-# Mbed TLS provides libmbedcrypto
+# MbedTLS provides libmbedcrypto
+set(MBEDTLS_USER_CONFIG_FILE "${TS_ROOT}/external/MbedTLS/config/crypto_posix.h"
+ CACHE STRING "Configuration file for mbedcrypto")
include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(ts-demo PRIVATE mbedcrypto)
+target_link_libraries(ts-demo PRIVATE MbedTLS::mbedcrypto)
#-------------------------------------------------------------------------------
# Define install content.
diff --git a/deployments/ts-demo/ts-demo.cpp b/deployments/ts-demo/ts-demo.cpp
index 7ccd7ddd7..55948a38d 100644
--- a/deployments/ts-demo/ts-demo.cpp
+++ b/deployments/ts-demo/ts-demo.cpp
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
*/
+#include <cstdio>
#include <service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h>
#include <protocols/rpc/common/packed-c/encoding.h>
#include <app/ts-demo/ts-demo.h>
@@ -18,18 +19,17 @@ int main(int argc, char *argv[]) {
service_locator_init();
- crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+ crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0");
if (crypto_service_context) {
- struct rpc_caller *caller;
- rpc_session_handle rpc_session_handle;
+ struct rpc_caller_session *session = NULL;
- rpc_session_handle = service_context_open(crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+ session = service_context_open(crypto_service_context);
- if (rpc_session_handle) {
+ if (session) {
- packedc_crypto_client crypto_client(caller);
+ packedc_crypto_client crypto_client(session);
status = run_ts_demo(&crypto_client, true);
@@ -37,7 +37,7 @@ int main(int argc, char *argv[]) {
printf("run_ts_demo failed\n");
}
- service_context_close(crypto_service_context, rpc_session_handle);
+ service_context_close(crypto_service_context, session);
}
else {
printf("Failed to open rpc session\n");
diff --git a/deployments/ts-fw-test/linux-pc/CMakeLists.txt b/deployments/ts-fw-test/linux-pc/CMakeLists.txt
new file mode 100644
index 000000000..2e918218f
--- /dev/null
+++ b/deployments/ts-fw-test/linux-pc/CMakeLists.txt
@@ -0,0 +1,87 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+include(../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Configure trace output
+#
+#-------------------------------------------------------------------------------
+set(TRACE_PREFIX "FW_TEST" CACHE STRING "Trace prefix")
+set(TRACE_LEVEL "TRACE_LEVEL_DEBUG" CACHE STRING "Trace level")
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the ts-fw-test deployment to run as a
+# userspace program in the linux-pc environment.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/linux-pc/env.cmake)
+project(trusted-services LANGUAGES CXX C)
+
+# Preparing firmware-test-build by including it
+include(${TS_ROOT}/external/firmware_test_builder/FirmwareTestBuilder.cmake)
+
+include(CTest)
+include(UnitTest)
+
+set(COVERAGE FALSE CACHE BOOL "Enable code coverage measurement")
+set(UNIT_TEST_PROJECT_PATH ${TS_ROOT} CACHE PATH "Path of the project directory")
+set(CMAKE_CXX_STANDARD 11)
+
+unit_test_init_cpputest()
+
+if (COVERAGE)
+ include(Coverage)
+
+ set(COVERAGE_FILE "coverage.info")
+ set(TS_SERVICE_TEST_COVERAGE_FILE "ts-fw-test-coverage.info" CACHE PATH "Path of coverage info file")
+ set(TS_SERVICE_TEST_COVERAGE_REPORT_DIR "${CMAKE_CURRENT_BINARY_DIR}/ts-fw-coverage-report" CACHE PATH "Directory of coverage report")
+
+ # Collecting coverage
+ coverage_generate(
+ NAME "ts-fw test"
+ SOURCE_DIR ${TS_ROOT}
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}
+ OUTPUT_FILE ${COVERAGE_FILE}
+ )
+
+ # Filtering project file coverage
+ coverage_filter(
+ INPUT_FILE ${COVERAGE_FILE}
+ OUTPUT_FILE ${TS_SERVICE_TEST_COVERAGE_FILE}
+ INCLUDE_DIRECTORY ${UNIT_TEST_PROJECT_PATH}/components
+ )
+
+ # Coverage report
+ coverage_generate_report(
+ INPUT_FILE ${TS_SERVICE_TEST_COVERAGE_FILE}
+ OUTPUT_DIRECTORY ${TS_SERVICE_TEST_COVERAGE_REPORT_DIR}
+ )
+endif()
+
+unit_test_add_suite(
+ NAME ts-fw-test
+)
+
+target_include_directories(ts-fw-test PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+#-------------------------------------------------------------------------------
+# Components that are specific to deployment in the linux-pc environment.
+#
+#-------------------------------------------------------------------------------
+add_components(
+ TARGET "ts-fw-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "environments/posix"
+)
+
+#-------------------------------------------------------------------------------
+# Extend with components that are common across all deployments of
+# ts-fw-test
+#
+#-------------------------------------------------------------------------------
+include(../ts-fw-test.cmake REQUIRED)
diff --git a/deployments/ts-fw-test/ts-fw-test.cmake b/deployments/ts-fw-test/ts-fw-test.cmake
new file mode 100644
index 000000000..41180e255
--- /dev/null
+++ b/deployments/ts-fw-test/ts-fw-test.cmake
@@ -0,0 +1,63 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# The base build file shared between deployments of 'ts-fw-test'. Used for
+# testing the fimware running on a separate DUT, exercised from test cases
+# that run on a host machine. This test configuration is suitable for test
+# scenarios that involve disruptive operations such as device restarts that
+# preclude
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Components that are common across all deployments
+#
+#-------------------------------------------------------------------------------
+add_components(
+ TARGET "ts-fw-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/endian"
+ "components/common/trace"
+ "components/common/utils"
+ "components/common/uuid"
+ "components/rpc/common/interface"
+ "components/rpc/common/caller"
+ "components/rpc/http/caller"
+ "components/rpc/http/caller/test"
+ "components/service/common/client"
+ "components/service/common/include"
+ "components/service/locator"
+ "components/service/locator/interface"
+ "components/service/locator/remote/restapi"
+ "components/service/fwu/test/fwu_client/remote"
+ "components/service/fwu/test/fwu_dut"
+ "components/service/fwu/test/fwu_dut/proxy"
+ "components/service/fwu/test/fwu_dut_factory/remote"
+ "components/service/fwu/test/image_directory_checker"
+ "components/service/fwu/test/metadata_checker"
+ "components/service/fwu/test/metadata_fetcher/client"
+)
+
+#-------------------------------------------------------------------------------
+# Installed package dependencies
+#
+#-------------------------------------------------------------------------------
+
+# Native CURL headers and libraries needed
+find_package(CURL REQUIRED)
+target_include_directories(ts-fw-test PRIVATE ${CURL_INCLUDE_DIR})
+target_link_libraries(ts-fw-test ${CURL_LIBRARIES})
+
+#-------------------------------------------------------------------------------
+# Define install content.
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS ts-fw-test RUNTIME DESTINATION ${TS_ENV}/bin)
diff --git a/deployments/ts-remote-test/arm-linux/CMakeLists.txt b/deployments/ts-remote-test/arm-linux/CMakeLists.txt
index 7540178f8..a44cb4cb4 100644
--- a/deployments/ts-remote-test/arm-linux/CMakeLists.txt
+++ b/deployments/ts-remote-test/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
@@ -27,5 +27,4 @@ include(../ts-remote-test.cmake REQUIRED)
# Define library options and dependencies.
#
#-------------------------------------------------------------------------------
-env_set_link_options(TGT ts-remote-test)
target_link_libraries(ts-remote-test PRIVATE stdc++ gcc m)
diff --git a/deployments/ts-remote-test/linux-pc/CMakeLists.txt b/deployments/ts-remote-test/linux-pc/CMakeLists.txt
index 5e5aaa5d8..92c1d3d61 100644
--- a/deployments/ts-remote-test/linux-pc/CMakeLists.txt
+++ b/deployments/ts-remote-test/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
diff --git a/deployments/ts-remote-test/ts-remote-test.cmake b/deployments/ts-remote-test/ts-remote-test.cmake
index 0f35bb2ab..0bdeb9bb2 100644
--- a/deployments/ts-remote-test/ts-remote-test.cmake
+++ b/deployments/ts-remote-test/ts-remote-test.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -13,11 +13,11 @@
#-------------------------------------------------------------------------------
# Use libts for locating and accessing services. An appropriate version of
-# libts will be imported for the enviroment in which tests are
+# libts will be imported for the environment in which tests are
# deployed.
#-------------------------------------------------------------------------------
include(${TS_ROOT}/deployments/libts/libts-import.cmake)
-target_link_libraries(ts-remote-test PRIVATE libts)
+target_link_libraries(ts-remote-test PRIVATE libts::ts)
#-------------------------------------------------------------------------------
# Common main for all deployments
@@ -28,7 +28,7 @@ target_sources(ts-remote-test PRIVATE
)
#-------------------------------------------------------------------------------
-# Components that are common accross all deployments
+# Components that are common across all deployments
#
#-------------------------------------------------------------------------------
add_components(
@@ -49,4 +49,4 @@ add_components(
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
endif()
-install(TARGETS ts-remote-test RUNTIME DESTINATION bin)
+install(TARGETS ts-remote-test RUNTIME DESTINATION ${TS_ENV}/bin)
diff --git a/deployments/ts-remote-test/ts-remote-test.cpp b/deployments/ts-remote-test/ts-remote-test.cpp
index 1c708f657..6240dfb95 100644
--- a/deployments/ts-remote-test/ts-remote-test.cpp
+++ b/deployments/ts-remote-test/ts-remote-test.cpp
@@ -19,18 +19,17 @@ int main(int argc, char *argv[]) {
service_locator_init();
- test_runner_service_context = service_locator_query("sn:trustedfirmware.org:test-runner:0", &status);
+ test_runner_service_context = service_locator_query("sn:trustedfirmware.org:test-runner:0");
if (test_runner_service_context) {
- struct rpc_caller *caller;
- rpc_session_handle rpc_session_handle;
+ struct rpc_caller_session *session = NULL;
- rpc_session_handle = service_context_open(test_runner_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+ session = service_context_open(test_runner_service_context);
- if (rpc_session_handle) {
+ if (session) {
- test_runner_client test_runner_client(caller);
+ test_runner_client test_runner_client(session);
remote_test_runner commandline_runner(&test_runner_client);
status = commandline_runner.execute(argc, argv);
@@ -39,7 +38,7 @@ int main(int argc, char *argv[]) {
printf("Command failed with test status: %d rpc status: %d\n", status, test_runner_client.err_rpc_status());
}
- service_context_close(test_runner_service_context, rpc_session_handle);
+ service_context_close(test_runner_service_context, session);
}
else {
printf("Failed to open rpc session\n");
diff --git a/deployments/ts-service-test/arm-linux/CMakeLists.txt b/deployments/ts-service-test/arm-linux/CMakeLists.txt
index 6a01d38aa..c76e79d6c 100644
--- a/deployments/ts-service-test/arm-linux/CMakeLists.txt
+++ b/deployments/ts-service-test/arm-linux/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
@@ -23,9 +23,7 @@ add_components(
BASE_DIR ${TS_ROOT}
COMPONENTS
"components/app/test-runner"
-# Running smm_variable tests currently requires kernel built with CONFIG_STRICT_DEVMEM=n
-# "components/service/smm_variable/client/cpp"
-# "components/service/smm_variable/test/service"
+ "components/service/fwu/test/fwu_dut_factory/remote"
)
include(${TS_ROOT}/external/CppUTest/CppUTest.cmake)
@@ -42,5 +40,4 @@ include(../ts-service-test.cmake REQUIRED)
# Define library options and dependencies.
#
#-------------------------------------------------------------------------------
-env_set_link_options(TGT ts-service-test)
target_link_libraries(ts-service-test PRIVATE stdc++ gcc m)
diff --git a/deployments/ts-service-test/linux-pc/CMakeLists.txt b/deployments/ts-service-test/linux-pc/CMakeLists.txt
index d9b60d6bd..b0cd912f7 100644
--- a/deployments/ts-service-test/linux-pc/CMakeLists.txt
+++ b/deployments/ts-service-test/linux-pc/CMakeLists.txt
@@ -1,10 +1,10 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
include(../../deployment.cmake REQUIRED)
#-------------------------------------------------------------------------------
@@ -71,17 +71,52 @@ unit_test_add_suite(
target_include_directories(ts-service-test PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
#-------------------------------------------------------------------------------
+# External project source-level dependencies
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/external/tf_a/tf-a.cmake)
+add_tfa_dependency(TARGET "ts-service-test")
+
+#-------------------------------------------------------------------------------
# Components that are specific to deployment in the linux-pc environment.
#
#-------------------------------------------------------------------------------
add_components(
TARGET "ts-service-test"
BASE_DIR ${TS_ROOT}
- COMPONENTS
+ COMPONENTS
+ "components/common/crc32"
"components/service/test_runner/client/cpp"
"components/service/test_runner/test/service"
- "components/service/smm_variable/client/cpp"
- "components/service/smm_variable/test/service"
+ "components/service/block_storage/block_store"
+ "components/service/block_storage/block_store/client"
+ "components/service/block_storage/block_store/partitioned"
+ "components/service/block_storage/block_store/device"
+ "components/service/block_storage/block_store/device/ram"
+ "components/service/block_storage/factory/client"
+ "components/service/block_storage/test/service"
+ "components/service/common/provider"
+ "components/service/fwu/agent"
+ "components/service/fwu/fw_store/banked"
+ "components/service/fwu/fw_store/banked/metadata_serializer/v1"
+ "components/service/fwu/fw_store/banked/metadata_serializer/v2"
+ "components/service/fwu/installer"
+ "components/service/fwu/installer/raw"
+ "components/service/fwu/installer/copy"
+ "components/service/fwu/inspector/direct"
+ "components/service/fwu/provider"
+ "components/service/fwu/provider/serializer/packed-c"
+ "components/service/fwu/test/fwu_client/direct"
+ "components/service/fwu/test/fwu_dut/sim"
+ "components/service/fwu/test/fwu_dut_factory/remote_sim"
+ "components/service/fwu/test/metadata_fetcher/volume"
+ "components/service/fwu/test/ref_scenarios"
+ "components/service/rpmb/backend/emulated"
+ "components/service/rpmb/provider"
+ "components/media/volume"
+ "components/media/volume/index"
+ "components/media/volume/base_io_dev"
+ "components/media/volume/block_volume"
)
#-------------------------------------------------------------------------------
diff --git a/deployments/ts-service-test/ts-service-test.cmake b/deployments/ts-service-test/ts-service-test.cmake
index 4a8c59c14..925cedd0d 100644
--- a/deployments/ts-service-test/ts-service-test.cmake
+++ b/deployments/ts-service-test/ts-service-test.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,30 +8,30 @@
#-------------------------------------------------------------------------------
# The base build file shared between deployments of 'ts-service-test' for
# different environments. Used for running end-to-end service-level tests
-# where test cases excerise trusted service client interfaces.
+# where test cases exercise trusted service client interfaces.
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Use libts for locating and accessing services. An appropriate version of
-# libts will be imported for the enviroment in which service tests are
+# libts will be imported for the environment in which service tests are
# deployed.
#-------------------------------------------------------------------------------
include(${TS_ROOT}/deployments/libts/libts-import.cmake)
-target_link_libraries(ts-service-test PRIVATE libts)
+target_link_libraries(ts-service-test PRIVATE libts::ts)
#-------------------------------------------------------------------------------
-# Components that are common accross all deployments
+# Components that are common across all deployments
#
#-------------------------------------------------------------------------------
add_components(
TARGET "ts-service-test"
BASE_DIR ${TS_ROOT}
COMPONENTS
+ "components/common/endian"
"components/common/tlv"
+ "components/common/uuid"
"components/service/common/client"
"components/service/common/include"
- "components/service/discovery/client"
- "components/service/discovery/test/service"
"components/service/crypto/include"
"components/service/crypto/test/service"
"components/service/crypto/test/service/protobuf"
@@ -53,6 +53,10 @@ add_components(
"components/service/attestation/client/psa"
"components/service/attestation/client/provision"
"components/service/attestation/test/service"
+ "components/service/rpmb/backend"
+ "components/service/rpmb/client"
+ "components/service/rpmb/frontend"
+ "components/service/rpmb/frontend/platform/default"
"protocols/service/crypto/protobuf"
"protocols/service/crypto/packed-c"
"components/service/secure_storage/include"
@@ -62,6 +66,13 @@ add_components(
"components/service/secure_storage/frontend/psa/ps"
"components/service/secure_storage/frontend/psa/ps/test"
"components/service/secure_storage/backend/secure_storage_client"
+ "components/service/fwu/test/service"
+ "components/service/fwu/test/fwu_client/remote"
+ "components/service/fwu/test/fwu_dut"
+ "components/service/fwu/test/fwu_dut/proxy"
+ "components/service/fwu/test/image_directory_checker"
+ "components/service/fwu/test/metadata_checker"
+ "components/service/fwu/test/metadata_fetcher/client"
)
#-------------------------------------------------------------------------------
diff --git a/deployments/uefi-test/arm-linux/CMakeLists.txt b/deployments/uefi-test/arm-linux/CMakeLists.txt
new file mode 100644
index 000000000..c555b3aff
--- /dev/null
+++ b/deployments/uefi-test/arm-linux/CMakeLists.txt
@@ -0,0 +1,42 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+include(../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the uefi-test deployment for arm-linux
+#
+# Used for building and running service level tests from Linux user-space
+# on an Arm platform with real deployments of UEFI SMM services
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/arm-linux/env.cmake)
+project(trusted-services LANGUAGES CXX C)
+add_executable(uefi-test)
+target_include_directories(uefi-test PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+add_components(
+ TARGET "uefi-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/app/test-runner"
+ )
+
+include(${TS_ROOT}/external/CppUTest/CppUTest.cmake)
+target_link_libraries(uefi-test PRIVATE CppUTest)
+
+#-------------------------------------------------------------------------------
+# Extend with components that are common across all deployments of
+# uefi-test
+#
+#-------------------------------------------------------------------------------
+include(../uefi-test.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# Define library options and dependencies.
+#
+#-------------------------------------------------------------------------------
+target_link_libraries(uefi-test PRIVATE stdc++ gcc m)
diff --git a/deployments/uefi-test/linux-pc/CMakeLists.txt b/deployments/uefi-test/linux-pc/CMakeLists.txt
new file mode 100644
index 000000000..c32d5d774
--- /dev/null
+++ b/deployments/uefi-test/linux-pc/CMakeLists.txt
@@ -0,0 +1,76 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+include(../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the uefi-test deployment for linux-pc
+#
+# Used for building and running service level tests in a native PC enviroment.
+# Tests can be run by running the built executable called "uefi-test"
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/linux-pc/env.cmake)
+project(trusted-services LANGUAGES CXX C)
+
+# Prevents symbols in the uefi-test executable overriding symbols with
+# with same name in libts during dynamic linking performed by the program
+# loader.
+set(CMAKE_C_VISIBILITY_PRESET hidden)
+
+# Preparing firmware-test-build by including it
+include(${TS_ROOT}/external/firmware_test_builder/FirmwareTestBuilder.cmake)
+
+include(CTest)
+include(UnitTest)
+
+set(COVERAGE FALSE CACHE BOOL "Enable code coverage measurement")
+set(UNIT_TEST_PROJECT_PATH ${TS_ROOT} CACHE PATH "Path of the project directory")
+set(CMAKE_CXX_STANDARD 11)
+
+unit_test_init_cpputest()
+
+if (COVERAGE)
+ include(Coverage)
+
+ set(COVERAGE_FILE "coverage.info")
+ set(UEFI_TEST_COVERAGE_FILE "uefi-test-coverage.info" CACHE PATH "Path of coverage info file")
+ set(UEFI_TEST_COVERAGE_REPORT_DIR "${CMAKE_CURRENT_BINARY_DIR}/uefi-test-coverage-report" CACHE PATH "Directory of coverage report")
+
+ # Collecting coverage
+ coverage_generate(
+ NAME "uefi-test"
+ SOURCE_DIR ${TS_ROOT}
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}
+ OUTPUT_FILE ${COVERAGE_FILE}
+ )
+
+ # Filtering project file coverage
+ coverage_filter(
+ INPUT_FILE ${COVERAGE_FILE}
+ OUTPUT_FILE ${UEFI_TEST_COVERAGE_FILE}
+ INCLUDE_DIRECTORY ${UNIT_TEST_PROJECT_PATH}/components
+ )
+
+ # Coverage report
+ coverage_generate_report(
+ INPUT_FILE ${UEFI_TEST_COVERAGE_FILE}
+ OUTPUT_DIRECTORY ${UEFI_TEST_COVERAGE_REPORT_DIR}
+ )
+endif()
+
+unit_test_add_suite(
+ NAME uefi-test
+)
+
+target_include_directories(uefi-test PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+#-------------------------------------------------------------------------------
+# Extend with components that are common across all deployments of
+# uefi-test
+#
+#-------------------------------------------------------------------------------
+include(../uefi-test.cmake REQUIRED)
diff --git a/deployments/uefi-test/uefi-test.cmake b/deployments/uefi-test/uefi-test.cmake
new file mode 100644
index 000000000..9e43d6f26
--- /dev/null
+++ b/deployments/uefi-test/uefi-test.cmake
@@ -0,0 +1,53 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# The base build file shared between deployments of 'uefi-test' for
+# different environments. Used for running end-to-end service-level tests
+# against SMM service providers that implement UEFI services such as smm
+# variable.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Use libts for locating and accessing services. An appropriate version of
+# libts will be imported for the enviroment in which service tests are
+# deployed.
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/deployments/libts/libts-import.cmake)
+target_link_libraries(uefi-test PRIVATE libts::ts)
+
+#-------------------------------------------------------------------------------
+# Options and variables
+#-------------------------------------------------------------------------------
+option(UEFI_AUTH_VAR "Enable variable authentication" ON)
+if (UEFI_AUTH_VAR)
+ target_compile_definitions(uefi-test PRIVATE
+ -DUEFI_AUTH_VAR
+ )
+endif()
+
+#-------------------------------------------------------------------------------
+# Components that are common accross all deployments
+#
+#-------------------------------------------------------------------------------
+add_components(
+ TARGET "uefi-test"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/service/uefi/smm_variable/client/cpp"
+ "components/service/uefi/smm_variable/test/service"
+ "components/common/uuid"
+)
+
+#-------------------------------------------------------------------------------
+# Define install content.
+#
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+install(TARGETS uefi-test RUNTIME DESTINATION ${TS_ENV}/bin)
diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css
index 93747c8d4..93774809d 100644
--- a/docs/_static/css/custom.css
+++ b/docs/_static/css/custom.css
@@ -1,5 +1,5 @@
/*-----------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -83,3 +83,19 @@
font-size: 6rem;
color: #343131;
}
+
+/* override table width restrictions */
+.wy-table-responsive table td, .wy-table-responsive table th {
+ white-space: normal;
+}
+
+.wy-table-responsive {
+ margin-bottom: 24px;
+ max-width: 100;
+ overflow: visible;
+}
+
+wy-table-bordered-all, .rst-content table.docutils {
+ max-width: 100%;
+ min-width: 100%;
+} \ No newline at end of file
diff --git a/docs/_static/images/tfm-contribution.png b/docs/_static/images/tfm-contribution.png
new file mode 100644
index 000000000..9fa52f95e
--- /dev/null
+++ b/docs/_static/images/tfm-contribution.png
Binary files differ
diff --git a/docs/_static/images/tfm-documentation.png b/docs/_static/images/tfm-documentation.png
new file mode 100644
index 000000000..925c52e8c
--- /dev/null
+++ b/docs/_static/images/tfm-documentation.png
Binary files differ
diff --git a/docs/_static/images/tfm-integration.png b/docs/_static/images/tfm-integration.png
new file mode 100644
index 000000000..a25f51261
--- /dev/null
+++ b/docs/_static/images/tfm-integration.png
Binary files differ
diff --git a/docs/_static/images/tfm-introduction.png b/docs/_static/images/tfm-introduction.png
new file mode 100644
index 000000000..73998eb7d
--- /dev/null
+++ b/docs/_static/images/tfm-introduction.png
Binary files differ
diff --git a/docs/_static/images/tfm-platform.png b/docs/_static/images/tfm-platform.png
new file mode 100644
index 000000000..5a5fa5f2b
--- /dev/null
+++ b/docs/_static/images/tfm-platform.png
Binary files differ
diff --git a/docs/_static/images/tfm-reference.png b/docs/_static/images/tfm-reference.png
new file mode 100644
index 000000000..b53eaa496
--- /dev/null
+++ b/docs/_static/images/tfm-reference.png
Binary files differ
diff --git a/docs/_static/images/tfm-release.png b/docs/_static/images/tfm-release.png
new file mode 100644
index 000000000..056bfac7e
--- /dev/null
+++ b/docs/_static/images/tfm-release.png
Binary files differ
diff --git a/docs/certification/index.rst b/docs/certification/index.rst
new file mode 100644
index 000000000..58f8f1fbe
--- /dev/null
+++ b/docs/certification/index.rst
@@ -0,0 +1,27 @@
+Platform Certification
+======================
+Various certification programmes exist to help platform vendors produce hardware
+and firmware that meets defined requirements for security and feature compatibility.
+By conforming to a set of testable criteria, platform vendors can make assurances to
+customers about the capabilities and security of their products.
+
+The Trusted Services project is an upstream source for service related components
+that can be integrated into platform firmware. Many of these components are important
+building blocks for meeting certification requirements. Reuse of components by
+downstream platform integration projects will help drive quality and security
+improvements, especially in areas covered by relevant certification programmes.
+
+Currently, the following certification programmes have been adopted by downstream
+platform integration projects:
+
+.. toctree::
+ :maxdepth: 1
+
+ psa-certified
+ system-ready
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/certification/psa-certified.rst b/docs/certification/psa-certified.rst
new file mode 100644
index 000000000..b1bce4c9b
--- /dev/null
+++ b/docs/certification/psa-certified.rst
@@ -0,0 +1,77 @@
+PSA Certified
+=============
+PSA Certified provides a framework for securing connected devices. Certification demonstrates
+that security best practices have been implemented, based on an independent security assessment.
+For more information, see: `PSA Certified`_.
+
+PSA Certified defines ten security goals that form the foundation for device security. The
+certification process involves an assessment that these security goals have been met. The
+Trusted Services project includes service provider components and reference integrations
+that a system integrator may use as the basis for creating a platform that meets these goals.
+
+PSA Goals
+---------
+The following table lists the ten security goals and how the Trusted Services
+project helps to achieve them:
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 1
+
+ * - PSA Certified Goal
+ - Trusted Services Contribution
+ * - Unique Identification
+ - | A unique device identity, assigned during manufacture, may be stored securely
+ | using the Secure Storage trusted service with a suitable platform provided backend.
+ * - Security Lifecycle
+ - | The Attestation trusted service provides an extensible framework for adding claims
+ | to a signed attestation report. The security lifecycle state claim is planned to be
+ | added in a future release.
+ * - Attestation
+ - | A remote third-party may obtain a trusted view of the security state of a device by
+ | obtaining a signed attestation token from the Attestation service.
+ * - Secure Boot
+ - | Secure boot relies on a hardware trust anchor such as a public key hash programmed into
+ | an OTP eFuse array. For firmware that uses TF-A, all firmware components are verified
+ | during the early boot phase.
+ * - Secure Update
+ - | Involves cooperation of a trusted service with other firmware components such as the
+ | boot loader.
+ * - Anti-Rollback
+ - | The Secure Storage service provider can be used with arbitrary storage backends, allowing
+ | platform specific storage to be used. Where the necessary hardware is available, roll-back
+ | protected storage can be provided with a suitable backend.
+ * - Isolation
+ - | The trusted services architectural model assumes that service isolation is implemented using
+ | a hardware backed secure processing environment. A secure partition managed by a Secure
+ | Partition Manager is one method for realizing isolation.
+ * - Interaction
+ - | The FF-A specification defines messaging and memory management primitives that enable
+ | secure interaction between partitions. Importantly, the secure partition manager provides
+ | a trusted view of the identity of a message sender, allowing access to be controlled.
+ * - Secure Storage
+ - | The Secure Storage service provider uses a pre-configured storage backend to provide
+ | an object store with suitable security properties. Two deployments of the secure storage
+ | provider (Internal Trusted Storage and Protected Storage) are included with platform
+ | specific storage backends.
+ * - Cryptographic Service
+ - | The Crypto service provider implements a rich set of cryptographic operations using
+ | a protected key store. Key usage is controlled based on the least privileges principle
+ | where usage flags constrain permitted operations.
+
+Conformance Test Support
+------------------------
+To support API level conformance testing, the `PSA Arch Test project`_ provides a rich set
+of test suites that allow service implementations to be tested. To facilitate running of
+PSA functional API tests, the psa-api-test deployment (see: :ref:`Test Executables`) is
+supported which integrates test suites with service clients. This can be used to run tests
+on a platform and collect tests results to provide visibility to an external assessor.
+
+--------------
+
+.. _`PSA Certified`: https://www.psacertified.org/
+.. _`PSA Arch Test project`: https://github.com/ARM-software/psa-arch-tests.git.
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/certification/system-ready.rst b/docs/certification/system-ready.rst
new file mode 100644
index 000000000..f41625ab4
--- /dev/null
+++ b/docs/certification/system-ready.rst
@@ -0,0 +1,27 @@
+SystemReady
+===========
+Arm SystemReady is a compliance certification programme that aims to promote a standardized
+view of a platform and its firmware (see: `Arm SystemReady`_). SystemReady may be applied across
+different classes of device, represented by different SystemReady bands, from resource constrained
+IoT devices through to servers. By standardizing the platform and its firmware, generic operating
+systems can be expected to 'just work' on any compliant device.
+
+SystemReady leverages existing open standards such as UEFI. The Trusted Services project
+includes service level components that enable UEFI SMM services to be realized, backed by PSA
+root-of-trust services. As an alternative to EDK2 StMM, the smm-gateway deployment presents
+UEFI compliant SMM service endpoints, backed by the generic Secure Storage and Crypto services.
+For more information, see:
+
+ * :ref:`Secure Partition Images`
+ * :ref:`UEFI SMM Services`
+
+The UEFI features supported by smm-gateway are designed to meet SystemReady requirements for
+the IR band (embedded IoT).
+
+--------------
+
+.. _`Arm SystemReady`: https://developer.arm.com/architectures/system-architectures/arm-systemready
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/conf.py b/docs/conf.py
index e35a28ed1..ee9a1aaf3 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# -- Metadata about this file ------------------------------------------------
-__copyright__ = "Copyright (c) 2020-2021 Arm Limited and Contributors."
+__copyright__ = "Copyright (c) 2020-2023 Arm Limited and Contributors."
__license__ = "SPDX-License-Identifier: BSD-3-Clause"
# Configuration file for the Sphinx documentation builder.
@@ -31,7 +31,7 @@ version=release
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.plantuml',
- 'sphinxcontrib.moderncmakedomain', 'sphinx.ext.todo']
+ 'sphinxcontrib.moderncmakedomain' ]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -91,7 +91,7 @@ html_static_path = ['_static']
#Add custom css for HTML. Used to allow full page width rendering
def setup(app):
- app.add_stylesheet('css/custom.css')
+ app.add_css_file('css/custom.css')
# -- Options for autosectionlabel --------------------------------------------
@@ -102,7 +102,3 @@ autosectionlabel_maxdepth = 1
# -- Options for plantuml ----------------------------------------------------
plantuml_output_format = 'svg_img'
-# -- Options for todo extension ----------------------------------------------
-
-# Display todos
-todo_include_todos = False
diff --git a/docs/deployments/index.rst b/docs/deployments/index.rst
new file mode 100644
index 000000000..bc98e6123
--- /dev/null
+++ b/docs/deployments/index.rst
@@ -0,0 +1,31 @@
+Deployments
+===========
+In the context of the Trusted Services project, a deployment represents a build of an
+assembly of components that is intended to run within a specific environment. Some
+deployments may be built for different platforms using platform specific components
+if needed. The concept of a deployment is general purpose and can be applied to building
+a wide range of targets such as secure partition images, user-space tools, shared libraries
+and test executables.
+
+Supported deployments are described on the following pages:
+
+.. toctree::
+ :maxdepth: 1
+
+ secure-partitions
+ test-executables
+ libraries
+ tools-demo-apps
+
+Related documentsments:
+
+ - :ref:`Project Structure`
+ - :ref:`Service Deployment Model`
+ - :ref:`Build Instructions`
+ - :ref:`Running Tests`
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/deployments/libraries.rst b/docs/deployments/libraries.rst
new file mode 100644
index 000000000..25902ef78
--- /dev/null
+++ b/docs/deployments/libraries.rst
@@ -0,0 +1,55 @@
+Libraries
+=========
+Some deployments build common functionality into libraries that may be used by
+other deployments or external applications. The following library deployments
+are currently supported:
+
+.. _libs-libts:
+
+libts
+-----
+Userspace applications that depend on trusted services may use *libts* for handling
+service discovery and RPC messaging. A major benefit to application developers is
+that *libts* entirely decouples client applications from details of where a service
+provider is deployed and how to communicate with it. All TS test executables and
+tools that interact with service providers use *libts*.
+
+To facilitate test and development within a native PC environment, the *libts*
+deployment for the *linux-pc* environment integrates a set of service providers
+into the library itself. From a client application's perspective, this looks
+exactly the same as when running on a target platform with service providers
+deployed in secure processing environments. For more information, see:
+:ref:`Service Locator`.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *linux-pc* - service providers integrated into library
+ * | *arm-linux* - communicates with service providers in secure processing environment
+ * - Used by
+ - * Userspace applications
+
+.. _libs-libsp:
+
+libsp
+-----
+*libsp* provides a functional interface for using FF-A messaging and memory
+management facilities. *libsp* is used in SP deployments. For more information, see:
+:ref:`libsp`.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *opteesp*
+ * - Used by
+ - * Secure partitions
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/deployments/secure-partitions.rst b/docs/deployments/secure-partitions.rst
new file mode 100644
index 000000000..7727de9f9
--- /dev/null
+++ b/docs/deployments/secure-partitions.rst
@@ -0,0 +1,139 @@
+Secure Partition Images
+=======================
+Secure partition (SP) deployments are concerned with building SP images that can
+be loaded and run under a secure partition manager such as Hafnium or OP-TEE.
+SP images will usually include service provider components that expose a
+service interface that may be reached using FF-A messages. A set of SP images
+will be loaded and verified by device firmware to provide the required services.
+
+The following deployments that create SP images are currently supported:
+
+crypto
+------
+An instance of the crypto service provider is built into an SP image to
+perform cryptographic operations on behalf of clients running in different
+partitions. Backend crypto operations are implemented by the crypto library
+component of MbedTLS. This deployment provides the cryptographic facilities
+needed for PSA certification. For more information, see:
+:ref:`Crypto Service`.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * *opteesp* (runs as an S-EL0 SP under OP-TEE)
+ * *sp* (SPMC agnostic S-EL0 SP format)
+ * - External Dependencies
+ - * | TRNG (platform specific)
+ * | Secure storage SP
+
+attestation
+-----------
+An instance of the attestation service provider is built into an SP image
+to support remote attestation use-cases. The service provider obtains a
+trusted view of the boot state of device firmware from the TPM event log
+collected by the boot loader. This deployment provides the initial attestation
+facility needed for PSA certification. For more information, see:
+:ref:`Attestation Service`.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * *opteesp* (runs as an S-EL0 SP under OP-TEE)
+ * *sp* (SPMC agnostic S-EL0 SP format)
+ * - External Dependencies
+ - * | TPM Event Log (via SP boot parameter)
+ * | Crypto SP
+
+internal-trusted-storage & protected-storage
+--------------------------------------------
+Two secure storage SP deployments are provided to allow different classes
+of storage to coexist on a device. Both deployments build an instance of
+the secure storage service provider with a storage backend. To allow
+different security trade-offs to be made and to support different hardware,
+a system integrator may configure which storage backend to use. Secure storage
+is a requirement for PSA certification. For more information, see:
+:ref:`Secure Storage Service`.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * *opteesp* (runs as an S-EL0 SP under OP-TEE)
+ * *sp* (SPMC agnostic S-EL0 SP format)
+ * - External Dependencies
+ - * Depends on configured storage backend
+
+se-proxy
+--------
+The se-proxy SP provides access to services hosted by a secure enclave (hence
+'se'). A secure enclave consists of a separate MCU, connected to the host via
+a secure communications channel. To protect access to the communication channel,
+the se-proxy SP is assigned exclusive access to the communication peripheral via
+device or memory regions defined in the SP manifest. The deployment integrates
+multiple service providers into the SP image. After performing access control,
+service requests are forwarded to the secure enclave.
+
+The se-proxy deployment includes proxies for the following services:
+
+ - Crypto
+ - Attestation
+ - Internal Trusted Storage
+ - Protected Storage
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * *opteesp* (runs as an S-EL0 SP under OP-TEE)
+ * *sp* (SPMC agnostic S-EL0 SP format)
+ * - External Dependencies
+ - * SE communication peripheral (platform specific)
+
+smm-gateway
+-----------
+An instance of the smm-variable service provider is built into the smm-gateway SP
+image to provide secure world backing for UEFI SMM services. The smm-gateway SP
+provides a lightweight alternative to StMM. For more information, see:
+:ref:`UEFI SMM Services`.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * *opteesp* (runs as an S-EL0 SP under OP-TEE)
+ * *sp* (SPMC agnostic S-EL0 SP format)
+ * - External Dependencies
+ - * | Secure storage service instance (e.g. hosted by protected-storage SP)
+ * | Crypto service instance (e.g. hosted crypto SP)
+
+env-test
+--------
+An instance of the test runner service provider is built into an SP image to
+allow test cases to be run from within the SP isolated environment. The SP
+image also includes environment and platform specific test cases to allow
+access to FF-A services and platform hardware to be tested. The test runner
+service provider is intended to be used in conjunction with a client that
+coordinates which tests to run and collects test results.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * *opteesp* (runs as an S-EL0 SP under OP-TEE)
+ * *sp* (SPMC agnostic S-EL0 SP format)
+ * - External Dependencies
+ - * Any hardware accessed by test cases (platform specific)
+
+--------------
+
+*Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/deployments/test-executables.rst b/docs/deployments/test-executables.rst
new file mode 100644
index 000000000..db569f375
--- /dev/null
+++ b/docs/deployments/test-executables.rst
@@ -0,0 +1,113 @@
+Test Executables
+================
+The Trusted Services project maintains a number of deployments concerned with
+test. Although there may be some coverage overlap between different deployments,
+in general, the built test executables corresponding to different deployments
+serve different purposes. Most test executables may be run either on target
+hardware or a development PC as a native application. For more information, see:
+:ref:`Running Tests`.
+
+The following test deployments are currently supported:
+
+component-test
+--------------
+The component-test deployment combines a large set of tests and components into
+a monolithic image that may be run as a userspace application. The CppUtest test
+framework is used for running tests and capturing results. The component-test
+executable may be built and run very quickly to obtain a first pass check for
+build failures or regressions.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *linux-pc*
+ * | *arm-linux*
+ * - Used for
+ - * | Build testing
+ * | Development support and debug
+ * | Regression testing
+
+ts-service-test
+---------------
+The ts-service-test deployment combines test suites that exercise service providers
+via their standard service interfaces where test cases perform the role of service client.
+Service discovery and RPC messaging is handled by the *libts* shared library. On real targets,
+the *libts* library uses a dynamic discovery mechanism to locate and communicate with real
+service deployments. For native PC builds, service providers are embedded into the *libts*
+library itself, allowing service level testing within a native PC environment.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *linux-pc* - tests against service providers integrated into *libts*
+ * | *arm-linux* - tests against real service deployments
+ * - Used for
+ - * | End-to-end service testing
+ * | Security testing
+ * | Development support and debug
+ * | Regression testing
+
+uefi-test
+---------
+The uefi-test deployment includes service level tests for UEFI SMM services.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *linux-pc* - tests against service providers integrated into *libts*
+ * | *arm-linux* - tests against real service deployments using MM_COMMUNICATE
+ * - Used for
+ - * | UEFI service level testing
+ * | Regression testing
+
+psa-api-test
+------------
+Used for PSA API conformance testing using test suites from: `PSA Arch Test project`_.
+Tests are integrated with service clients to enable end-to-end testing against deployed
+service providers. Separate executables are built for each API under test. As with
+ts-service-test and uefi-test, service discovery and messaging is handled by *libts*,
+allowing API tests to be run on real targets or within a native PC environment.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *linux-pc* - tests against service providers integrated into *libts*
+ * | *arm-linux* - tests against real service deployments
+ * - Used for
+ - * | PSA API conformance testing
+ * | Regression testing
+
+ts-remote-test
+--------------
+The ts-remote-test deployment builds a userspace application that allows a remote
+test runner to be discovered and controlled. It implements a subset of the the
+CppUtest command line interface but instead of running tests directly, it
+communicates with the remote test runner to run tests and collect results. Can
+be used, for example, to control the running of tests included in the env-test
+deployment.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *linux-pc* - tests against test runner service provider integrated into *libts*
+ * | *arm-linux* - tests against real test runner deployment e.g. env-test
+ * - Used for
+ - * | Running environment tests
+
+--------------
+
+.. _`PSA Arch Test project`: https://github.com/ARM-software/psa-arch-tests.git
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/deployments/tools-demo-apps.rst b/docs/deployments/tools-demo-apps.rst
new file mode 100644
index 000000000..f3c3adf7c
--- /dev/null
+++ b/docs/deployments/tools-demo-apps.rst
@@ -0,0 +1,41 @@
+Tools & Demo Applications
+=========================
+The following deployments are concerned with building tools and demo applications.
+
+platform-inspect
+----------------
+The *platform-inspect* tool may be run from a Linux terminal to inspect and
+report information about platform firmware. Functionality is currently limited
+to retrieving a firmware attestation report and printing its contents.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *linux-pc*
+ * | *arm-linux*
+ * - Used for
+ - * | Obtaining information about platform firmware
+
+ts-demo
+-------
+*ts-demo* is a simple application that uses the Crypto service to perform some
+typical sign, verify and encrypt operations. It is intended to be used as an
+example of how trusted services can be used by userspace applications.
+
+.. list-table::
+ :widths: 1 2
+ :header-rows: 0
+
+ * - Supported Environments
+ - * | *linux-pc*
+ * | *arm-linux*
+ * - Used for
+ - * | Provides an example for how to use trusted services
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/arch-overview.rst b/docs/developer/arch-overview.rst
index d2f8c4d17..c1f985a91 100644
--- a/docs/developer/arch-overview.rst
+++ b/docs/developer/arch-overview.rst
@@ -9,7 +9,7 @@ and its environment. The model allows applications to be deployed in a diverse
featured trusted OSs, such as OP-TEE, to bare metal secure partitions.
For a more in-depth description of how the ports and adapters pattern is applied, see:
-:ref:`Portability Model`
+:ref:`Service Deployment Model`
Service Model
-------------
@@ -74,6 +74,6 @@ message protocols using Google Protocol Buffers and packed C structures have bee
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/build-instructions.rst b/docs/developer/build-instructions.rst
index 5fe6c634a..f52fe5529 100644
--- a/docs/developer/build-instructions.rst
+++ b/docs/developer/build-instructions.rst
@@ -25,6 +25,39 @@ different environments:
.. uml:: uml/BuildFlow.puml
+Selecting the build type
+-------------------------
+The build type selects code optimization and debug information related compiler settings. The build system follows the
+standard CMake methodology and uses the `CMAKE_BUILD_TYPE`_ variable.
+
+The build system uses the following build types:
+
+.. list-table:: Supported build types
+ :header-rows: 1
+
+ * - Build type
+ - Purpose
+ - Description
+ * - Debug
+ - For debugging purposes.
+ - Optimization is off, debugging information generation is enabled.
+ * - MinSizeRel
+ - Size optimized release build.
+ - Optimization is configured to prefer small code size, debugging information is not generated.
+ * - MinSizWithDebInfo
+ - For debugging size optimized release build.
+ - Optimization is configured to prefer small code size, debugging information generation is enabled.
+ * - Release
+ - Speed optimized release build.
+ - Optimization is configured to prefer execution speed, debugging information is not generated.
+ * - RelWithDebugInfo
+ - For debugging speed optimized release build.
+ - Optimization is configured to prefer execution speed, debugging information generation is enabled.
+
+Build type of external components can be configured with command line parameters. Parameter names follow this pattern:
+``-D<upper case component name>_BUILD_TYPE=<value>`` e.g. ``-DNANOPB_BUILD_TYPE=Release``. Supported values are
+component specific, please refer to the appropriate cmake file under ``<TS_ROOT>/external/<name>``.
+
Building and Installing
-----------------------
When building from a clean environment where no generated build files exist, it is necessary to run
@@ -122,10 +155,10 @@ Some example deployment methods are:
directly accessible by the target.
* Installed files are incorporated into a third-party build process e.g. OP-TEE.
-The following guides provide instructions on deploying to different environments:
+The following guides provide instructions on deploying services and running programs on FVP:
* :ref:`Deploying trusted services in S-EL0 Secure Partitions under OP-TEE`
-* :ref:`Deploying Programs on FVP`
+* :ref:`Running User-space Programs on FVP`
Batch Building
--------------
@@ -135,6 +168,8 @@ more information, see
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+.. _CMAKE_BUILD_TYPE: https://cmake.org/cmake/help/v3.18/variable/CMAKE_BUILD_TYPE.html
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/deployments.rst b/docs/developer/deployments.rst
deleted file mode 100644
index 74fdeb3d1..000000000
--- a/docs/developer/deployments.rst
+++ /dev/null
@@ -1,49 +0,0 @@
-Deployments
-===========
-In the context of the Trusted Services project, a deployment represents a unit of functionality
-that is built for a specific environment. You can find out more about deployments here
-:ref:`Project Structure`.
-
-The following table lists currently supported deployments:
-
-.. list-table:: Supported deployments
- :header-rows: 1
-
- * - Deployment Name
- - Environments
- - Provides
- - Used for
- * - component-test
- - linux-pc, arm-linux
- - Standalone tests for components and integrations
- - Test driven development and regression testing
- * - ts-service-test
- - linux-pc, arm-linux
- - Service API level tests
- - Tests services from perspective of client application
- * - ts-demo
- - linux-pc, arm-linux
- - Demonstration client application
- - Example user-space client application
- * - libts
- - linux-pc, arm-linux
- - Provides standard client interface for locating services and establishing RPC sessions
- - Client application development
- * - crypto
- - opteesp
- - Crypto trusted service
- - Production deployments
- * - secure-storage
- - opteesp
- - Secure storage trusted service
- - Production deployments
- * - libsp
- - opteesp
- - FF-A interface library
- - FF-A library used in secure partition environments
-
---------------
-
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
-
-SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/image/TSProtocolLayers.svg b/docs/developer/image/TSProtocolLayers.svg
new file mode 100644
index 000000000..9ecebde1d
--- /dev/null
+++ b/docs/developer/image/TSProtocolLayers.svg
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1241px" height="731px" viewBox="-0.5 -0.5 1241 731" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="630" y="0" width="610" height="100" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 608px; height: 1px; padding-top: 7px; margin-left: 632px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Service backend</div></div></div></foreignObject><text x="632" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Service backend</text></switch></g><rect x="0" y="0" width="610" height="100" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 608px; height: 1px; padding-top: 7px; margin-left: 2px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Service client interface</div></div></div></foreignObject><text x="2" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Service client interface</text></switch></g><rect x="0" y="150" width="1240" height="100" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 1238px; height: 1px; padding-top: 157px; margin-left: 2px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Service layer</div></div></div></foreignObject><text x="2" y="169" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Service layer</text></switch></g><rect x="0" y="280" width="1240" height="310" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 1238px; height: 1px; padding-top: 287px; margin-left: 2px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">RPC layer</div></div></div></foreignObject><text x="2" y="299" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">RPC layer</text></switch></g><rect x="0" y="610" width="1240" height="120" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 1238px; height: 1px; padding-top: 617px; margin-left: 2px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A layer<br /></div></div></div></foreignObject><text x="2" y="629" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">FF-A layer&#xa;</text></switch></g><path d="M 705 650 L 763.63 650" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 768.88 650 L 761.88 653.5 L 763.63 650 L 761.88 646.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 630 630 C 606 630 600 650 619.2 654 C 600 662.8 621.6 682 637.2 674 C 648 690 684 690 696 674 C 720 674 720 658 705 650 C 720 634 696 618 675 626 C 660 614 636 614 630 630 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 650px; margin-left: 601px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A</div></div></div></foreignObject><text x="660" y="654" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A</text></switch></g><path d="M 830 620 L 830 486.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 830 481.12 L 833.5 488.12 L 830 486.37 L 826.5 488.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="770" y="620" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 650px; margin-left: 771px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">libsp</div></div></div></foreignObject><text x="830" y="654" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">libsp</text></switch></g><path d="M 550 650 L 575 650 L 575 654 L 612.83 654" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 618.08 654 L 611.08 657.5 L 612.83 654 L 611.08 650.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="440" y="620" width="110" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 650px; margin-left: 441px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">libsp</div></div></div></foreignObject><text x="495" y="654" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">libsp</text></switch></g><path d="M 150 680 L 150 720 L 666 720 L 666 692.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 666 687.12 L 669.5 694.12 L 666 692.37 L 662.5 694.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="90" y="620" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 650px; margin-left: 91px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Linux FF-A driver</div></div></div></foreignObject><text x="150" y="654" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Linux FF-A driver</text></switch></g><path d="M 150 580 L 150 613.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 150 618.88 L 146.5 611.88 L 150 613.63 L 153.5 611.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="90" y="520" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 550px; margin-left: 91px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">TS TEE driver</div></div></div></foreignObject><text x="150" y="554" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">TS TEE driver</text></switch></g><path d="M 515 480 L 515 550 L 495 550 L 495 613.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 495 618.88 L 491.5 611.88 L 495 613.63 L 498.5 611.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="460" y="420" width="110" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 450px; margin-left: 461px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">ts_rpc_caller_sp</div></div></div></foreignObject><text x="515" y="454" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">ts_rpc_caller_sp</text></switch></g><path d="M 800 420 L 800 236.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 800 231.12 L 803.5 238.12 L 800 236.37 L 796.5 238.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 830 420 L 830 270 L 970 270 L 970 236.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 970 231.12 L 973.5 238.12 L 970 236.37 L 966.5 238.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 860 420 L 860 310 L 1110 310 L 1110 236.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1110 231.12 L 1113.5 238.12 L 1110 236.37 L 1106.5 238.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="770" y="420" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 450px; margin-left: 771px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">ts_rpc_endpoint_sp</div></div></div></foreignObject><text x="830" y="454" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">ts_rpc_endpoint_sp</text></switch></g><path d="M 830 170 L 830 86.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 830 81.12 L 833.5 88.12 L 830 86.37 L 826.5 88.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="770" y="170" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 771px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Attestation<br />RPC service</div></div></div></foreignObject><text x="830" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Attestation...</text></switch></g><path d="M 970 170 L 970 86.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 970 81.12 L 973.5 88.12 L 970 86.37 L 966.5 88.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="910" y="170" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 911px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Crypto<br />RPC service</div></div></div></foreignObject><text x="970" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Crypto...</text></switch></g><path d="M 1110 170 L 1110 86.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1110 81.12 L 1113.5 88.12 L 1110 86.37 L 1106.5 88.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="1050" y="170" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 1051px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Storage<br />RPC service</div></div></div></foreignObject><text x="1110" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Storage...</text></switch></g><path d="M 150 480 L 150 513.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 150 518.88 L 146.5 511.88 L 150 513.63 L 153.5 511.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="90" y="420" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 450px; margin-left: 91px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">ts_rpc_caller_linux</div></div></div></foreignObject><text x="150" y="454" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">ts_rpc_caller_linux</text></switch></g><rect x="770" y="20" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 771px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Attestation<br />backend</div></div></div></foreignObject><text x="830" y="54" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Attestation...</text></switch></g><rect x="910" y="20" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 911px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Crypto<br />backend</div></div></div></foreignObject><text x="970" y="54" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Crypto...</text></switch></g><rect x="1050" y="20" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 1051px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Storage<br />backend</div></div></div></foreignObject><text x="1110" y="54" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Storage...</text></switch></g><path d="M 190 230 L 190 265 L 302.5 265 L 302.5 293.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 302.5 298.88 L 299 291.88 L 302.5 293.63 L 306 291.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="130" y="170" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 131px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Attestation<br />RPC caller</div></div></div></foreignObject><text x="190" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Attestation...</text></switch></g><path d="M 330 230 L 330 293.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 330 298.88 L 326.5 291.88 L 330 293.63 L 333.5 291.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="270" y="170" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 271px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Crypto<br />RPC caller</div></div></div></foreignObject><text x="330" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Crypto...</text></switch></g><path d="M 470 230 L 470 265 L 357.5 265 L 357.5 293.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 357.5 298.88 L 354 291.88 L 357.5 293.63 L 361 291.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="410" y="170" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 411px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Storage<br />RPC caller</div></div></div></foreignObject><text x="470" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Storage...</text></switch></g><path d="M 190 80 L 190 163.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 190 168.88 L 186.5 161.88 L 190 163.63 L 193.5 161.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="130" y="20" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 131px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Attestation<br />client</div></div></div></foreignObject><text x="190" y="54" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Attestation...</text></switch></g><path d="M 330 80 L 330 163.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 330 168.88 L 326.5 161.88 L 330 163.63 L 333.5 161.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="270" y="20" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 271px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Crypto<br />client</div></div></div></foreignObject><text x="330" y="54" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Crypto...</text></switch></g><path d="M 470 80 L 470 163.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 470 168.88 L 466.5 161.88 L 470 163.63 L 473.5 161.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="410" y="20" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 411px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Storage<br />client</div></div></div></foreignObject><text x="470" y="54" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Storage...</text></switch></g><rect x="220" y="420" width="110" height="60" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 450px; margin-left: 221px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">direct</div></div></div></foreignObject><text x="275" y="454" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">direct</text></switch></g><rect x="340" y="420" width="110" height="60" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 450px; margin-left: 341px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">dummy</div></div></div></foreignObject><text x="395" y="454" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">dummy</text></switch></g><path d="M 302.5 360 L 302.5 390 L 150 390 L 150 413.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 150 418.88 L 146.5 411.88 L 150 413.63 L 153.5 411.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 357.5 360 L 357.5 390 L 515 390 L 515 413.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 515 418.88 L 511.5 411.88 L 515 413.63 L 518.5 411.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="275" y="300" width="110" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 330px; margin-left: 276px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">rpc_caller_session</div></div></div></foreignObject><text x="330" y="334" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">rpc_caller_session</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/developer/image/TSServiceDiscovery.svg b/docs/developer/image/TSServiceDiscovery.svg
new file mode 100644
index 000000000..d9e4b7e54
--- /dev/null
+++ b/docs/developer/image/TSServiceDiscovery.svg
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1681px" height="661px" viewBox="-0.5 -0.5 1681 661" style="background-color: rgb(255, 255, 255);"><defs/><g><path d="M 1160.05 80 L 1160.1 180 L 840 180 L 840 268.03" fill="none" stroke="#82b366" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 840 275.53 L 835 265.53 L 840 268.03 L 845 265.53 Z" fill="#82b366" stroke="#82b366" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 1180 80 L 1180 268.03" fill="none" stroke="#82b366" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1180 275.53 L 1175 265.53 L 1180 268.03 L 1185 265.53 Z" fill="#82b366" stroke="#82b366" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 1199.95 79.04 L 1200 180 L 1520 180 L 1520 268.03" fill="none" stroke="#82b366" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1520 275.53 L 1515 265.53 L 1520 268.03 L 1525 265.53 Z" fill="#82b366" stroke="#82b366" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 1105.75 68.28 L 500 68.3 L 500 273.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 500 278.88 L 496.5 271.88 L 500 273.63 L 503.5 271.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1075 40 L 160 40 L 160 273.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 160 278.88 L 156.5 271.88 L 160 273.63 L 163.5 271.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 680 330 L 680 280 L 1000 280 L 1000 330" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><path d="M 680 330 L 680 510 L 1000 510 L 1000 330" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="none"/><path d="M 680 330 L 1000 330" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="839.5" y="302.5">TS SP</text><text x="839.5" y="316.5">FF-A UUID = bdcd76d7-825e-4751-963b-86d4f84943ac</text></g><rect x="700" y="350" width="280" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 278px; height: 1px; padding-top: 380px; margin-left: 702px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Attestation service<br />Interface ID = 0<br />UUID = a1baf155-8876-4695-8f7c-54955e8db974</div></div></div></foreignObject><text x="702" y="384" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Attestation service...</text></switch></g><rect x="700" y="430" width="280" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 278px; height: 1px; padding-top: 460px; margin-left: 702px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Crypto service<br />Interface ID = 1<br /><div style=""><span style="background-color: initial;">UUID = d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0</span></div></div></div></div></foreignObject><text x="702" y="464" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Crypto service...</text></switch></g><path d="M 1020 330 L 1020 280 L 1340 280 L 1340 330" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="none"/><path d="M 1020 330 L 1020 510 L 1340 510 L 1340 330" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="none"/><path d="M 1020 330 L 1340 330" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="1179.5" y="302.5">TS SP</text><text x="1179.5" y="316.5">FF-A UUID = bdcd76d7-825e-4751-963b-86d4f84943ac</text></g><rect x="1040" y="350" width="280" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 278px; height: 1px; padding-top: 380px; margin-left: 1042px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Protected storage<br />Interface ID = 0<br />UUID = 751bf801-3dde-4768-a514-0f10aeed1790</div></div></div></foreignObject><text x="1042" y="384" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Protected storage...</text></switch></g><rect x="1040" y="430" width="280" height="60" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 278px; height: 1px; padding-top: 460px; margin-left: 1042px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Internal trusted storage<br />Interface ID = 1<br /><div style=""><span style="background-color: initial;">UUID = dc1eef48-b17a-5ccf-ac8b-dfcff7711b14</span></div></div></div></div></foreignObject><text x="1042" y="464" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Internal trusted storage...</text></switch></g><path d="M 1360 330 L 1360 280 L 1680 280 L 1680 330" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="none"/><path d="M 1360 330 L 1360 510 L 1680 510 L 1680 330" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="none"/><path d="M 1360 330 L 1680 330" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="1519.5" y="302.5">TS SP</text><text x="1519.5" y="316.5">FF-A UUID = bdcd76d7-825e-4751-963b-86d4f84943ac</text></g><rect x="1380" y="350" width="280" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 278px; height: 1px; padding-top: 380px; margin-left: 1382px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Crypto service<br />Interface ID = 0<br /><div style=""><span style="background-color: initial;">UUID = d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0</span></div></div></div></div></foreignObject><text x="1382" y="384" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Crypto service...</text></switch></g><rect x="340" y="280" width="320" height="50" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 318px; height: 1px; padding-top: 305px; margin-left: 341px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Non-TS SP<br />FF-A UUID = <span style="background-color: initial;">020b365f-e907-4f7e-999d-20fbb7a03183<br /></span></div></div></div></foreignObject><text x="500" y="309" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Non-TS SP...</text></switch></g><rect x="0" y="280" width="320" height="50" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 318px; height: 1px; padding-top: 305px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Non-TS SP<br />FF-A UUID = <span style="background-color: initial;">444ca317-4205-4a7b-b263-a80ec7b0e776<br /></span></div></div></div></foreignObject><text x="160" y="309" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Non-TS SP...</text></switch></g><ellipse cx="1180" cy="40" rx="105" ry="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 40px; margin-left: 1076px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Phase 1.<br />FFA_PARTITION_INFO_GET<br />Select TS SPs by FF-A UUID</div></div></div></foreignObject><text x="1180" y="44" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Phase 1....</text></switch></g><path d="M 1180 560 L 1180 501.97" fill="none" stroke="#82b366" stroke-width="4" stroke-miterlimit="10" pointer-events="none"/><path d="M 1180 494.47 L 1185 504.47 L 1180 501.97 L 1175 504.47 Z" fill="#82b366" stroke="#82b366" stroke-width="4" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="1180" cy="610" rx="123" ry="50" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 244px; height: 1px; padding-top: 610px; margin-left: 1058px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Phase 2.<br />Select service of a TS SP by service UUID (Get service info query)</div></div></div></foreignObject><text x="1180" y="614" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Phase 2....</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/developer/image/TSportabilityModel.svg b/docs/developer/image/TSportabilityModel.svg
index e0635c552..d8fcbb69b 100644
--- a/docs/developer/image/TSportabilityModel.svg
+++ b/docs/developer/image/TSportabilityModel.svg
@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="471px" height="371px" viewBox="-0.5 -0.5 471 371" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2021-01-21T15:49:55.792Z&quot; agent=&quot;Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0&quot; etag=&quot;T4OmEHaxOAbJXEuewn-x&quot; version=&quot;12.7.1.1&quot; type=&quot;atlas&quot;&gt;&lt;mxAtlasLibraries/&gt;&lt;diagram id=&quot;Fh55IqWZiI4TxFe46PeK&quot; name=&quot;Page-1&quot;&gt;7Zpbc5s4FIB/jWe2D+4YZMf2Y25tZrbddSftNN2XjAwyaAuICvlCf/1KRsIg4ZikxgRv8xLpoAv6zjnSOTI9cB1u3lMY+x+Ji4KePXA3PXDTs21rZA35PyFJpQRYk0ziUexK2U5wj38iKRxI6RK7KCk1ZIQEDMdloUOiCDmsJIOUknW52YIE5Vlj6MkZBzvBvQMDZDT7il3mZ9LJqND6DmHPVzNbA/kkhKqxFCQ+dMm6IAK3PXBNCWFZKdxco0DQU1yyfu/2PM1fjKKI1elAfvzzJ/2azsm3VTL8Mr999B/Tvp2NsoLBUi74M10mDLlceI/oCjuIl2aUrLgaaM++CPhcV3NR8kTpDxjHAXYgwyR6I9fJUgWPLzkWRR9toEci3j5GFIeI8aFy6UyJOJGrtY8Zuo+hI7qtuU1xmc/CgNcsXnQx5UrGYqibhCwF4SuTg0SzQpShTUEkubxHhM9HU95EPgVSRdJIh7K63incmkiZX1B2bqRQGpmXj7zTAy9IVTxDLSNDLe2wXeAguCYBEUNGJELHwd0flnn3wcgADuwK4GDcFPALA/httMKURKFYps6er5OV4SWMku9IQ1VBDwbYE4AdPqxQ1JWgxv0nuJQPQuy6YppKbVGyjFwk1jE4jiby3Upqwh6bpj+ssvym9DA29ABdGAtUug7KLA7YdjN2nGNINZoFeqNT0pt0ml7FtntSetNO05u0TE+dhd3A1wevzHUtq9P42vZdywxku4SvdecFBr5ZANmC0NDgdzbBj32hhaF2y8GPSpafCvv5MDz13ceoecu1NNOdmqF7leWCxpjVSJVQ5F6KqwBhegFMEuyUUaENZg+F8jdhY29HsnazkSa3raSqEvG3fyhWCr1EdddtW1P99uqAp1zUQTWsg0HqIVbjJEauutrYo9MDOlMyivhWgFflC5EqRcoZZgSLnGmvyQwHmjFkS5fdijcY+kiT8kBgpA2UoTEG2hpWvu5fsDUzSzze6dKzwWL7d6TNTY9vTD+tyrAbu9GwzNykM+yGbbMzM5POsJu0zE5N1g12rw2emZR0B17bXqtYdRJe28eFbSYkBrwDuGASZz8ILfBGIG6SH88/NYBVV9qnjIvtOrnEWcTFylQOx8VyxN9x8ZHjYrtODvaSvPXYu5wGPN++DjhpYwm/XSOhaNRJrVM56bSmjypTOjsfHWo+ahjVHh/luodpoVksGiT73xhY2kE0HTz5Xnp77SsCXsje4Lgbhvkzn2H31CfhfJm0umH0tVPdrgiLTnuq18gE1YcBThrgyN3esx4gOM+i0A/zXACd7942Nv17yfgoqHnUQEM9td/WC0FVoHV01qBG/H4eEdS47uY8PdPNue0ACtTIds7DrS3Qvl//bzKjSU2/Vub3269f7tfj9Mt0Pftr/u8D++xfkk8f7+5oxdeVL7a0wTMs7eUWowKzV2sJ+oVTbUvQf3GfNhN+6xZnfJR7oL0Wrj83/ObV3QfFWfPdd9ng9j8=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 197.5 90 L 302.5 90 L 355 180 L 302.5 270 L 197.5 270 L 145 180 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" transform="rotate(90,250,180)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 180px; margin-left: 161px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Trusted Service Provider<br />(application)</div></div></div></foreignObject><text x="250" y="184" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Trusted Service Provider...</text></switch></g><path d="M 157.5 25 L 342.5 25 L 435 185 L 342.5 345 L 157.5 345 L 65 185 Z" fill="none" stroke="#000000" stroke-miterlimit="10" transform="rotate(90,250,185)" pointer-events="all"/><rect x="230" y="305" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 315px; margin-left: 231px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Environment</div></div></div></foreignObject><text x="250" y="319" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Enviro...</text></switch></g><rect x="350" y="135" width="50" height="20" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 145px; margin-left: 351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">adapter</div></div></div></foreignObject><text x="375" y="149" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="350" y="175" width="50" height="20" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 185px; margin-left: 351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">adapter</div></div></div></foreignObject><text x="375" y="189" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="350" y="215" width="50" height="20" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 225px; margin-left: 351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">adapter</div></div></div></foreignObject><text x="375" y="229" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="100" y="135" width="50" height="20" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 145px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">adapter</div></div></div></foreignObject><text x="125" y="149" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="100" y="175" width="50" height="20" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 185px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">adapter</div></div></div></foreignObject><text x="125" y="189" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="100" y="215" width="50" height="20" fill="none" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 225px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">adapter</div></div></div></foreignObject><text x="125" y="229" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="390" y="15" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 25px; margin-left: 391px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Platform</div></div></div></foreignObject><text x="410" y="29" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Platfo...</text></switch></g><ellipse cx="25" cy="145" rx="25" ry="15" fill="transparent" stroke="#000000" pointer-events="all"/><path d="M 50 145 L 93.63 145" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 98.88 145 L 91.88 148.5 L 93.63 145 L 91.88 141.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="150" y="140" width="20" height="10" fill="#ffffff" stroke="#000000" pointer-events="all"/><rect x="150" y="180" width="20" height="10" fill="#ffffff" stroke="#000000" pointer-events="all"/><rect x="150" y="220" width="20" height="10" fill="#ffffff" stroke="#000000" pointer-events="all"/><rect x="330" y="220" width="20" height="10" fill="#ffffff" stroke="#000000" pointer-events="all"/><rect x="330" y="180" width="20" height="10" fill="#ffffff" stroke="#000000" pointer-events="all"/><rect x="330" y="140" width="20" height="10" fill="#ffffff" stroke="#000000" pointer-events="all"/><rect x="10" y="170" width="30" height="30" fill="#ffffff" stroke="#000000" pointer-events="all"/><path d="M 40 185 L 93.63 185" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 98.88 185 L 91.88 188.5 L 93.63 185 L 91.88 181.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="375" cy="255" rx="15" ry="10" fill="#ffffff" stroke="#000000" pointer-events="all"/><path d="M 400 225 L 430 225 Q 440 225 440 235 L 440 245 Q 440 255 430 255 L 396.37 255" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 391.12 255 L 398.12 251.5 L 396.37 255 L 398.12 258.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 125 240 L 140 255 L 125 270 L 110 255 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 450 134.5 C 450 125.17 470 125.17 470 134.5 L 470 155.5 C 470 164.83 450 164.83 450 155.5 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 450 134.5 C 450 141.5 470 141.5 470 134.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 400 145 L 443.63 145" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 448.88 145 L 441.88 148.5 L 443.63 145 L 441.88 141.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 450 174.5 C 450 165.17 470 165.17 470 174.5 L 470 195.5 C 470 204.83 450 204.83 450 195.5 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 450 174.5 C 450 181.5 470 181.5 470 174.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 400 185 L 443.63 185" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 448.88 185 L 441.88 188.5 L 443.63 185 L 441.88 181.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 110 255 L 60 255 Q 50 255 50 245 L 50 235 Q 50 225 60 225 L 93.63 225" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 98.88 225 L 91.88 228.5 L 93.63 225 L 91.88 221.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="471px" height="371px" viewBox="-0.5 -0.5 471 371" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2022-09-02T12:38:49.699Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;gZJ4USVuZGaly2bdFk2b&quot; version=&quot;20.1.4&quot; type=&quot;atlas&quot;&gt;&lt;mxAtlasLibraries/&gt;&lt;diagram id=&quot;Fh55IqWZiI4TxFe46PeK&quot; name=&quot;Page-1&quot;&gt;7Zpbk5s2FIB/jWfaB2cMwmv7cW/Ndtq07mwy2fQlI4MMagBRIV/Ir69kJAwSjtmNMYubfVnpoAv6zjnSOTIDcBtt31KYBO+Ih8KBPfK2A3A3sG1rDAD/JySZlNjAySU+xZ6U7QWP+CuSwpGUrrCH0kpDRkjIcFIVuiSOkcsqMkgp2VSbLUlYnTWBvpxxtBc8ujBERrOP2GNBLp2OS60fEPYDNbM1kk8iqBpLQRpAj2xKInA/ALeUEJaXou0tCgU9xSXv98uBp8WLURSzJh3Iv3//Rj9mC/JpnTofFvefg8/Z0M5HWcNwJRf8nq5ShjwufER0jV3ES3NK1lwNdGBfhXyum4Uo+aL0E0ySELuQYRL/LNfJMgWPLzkRxQBtoU9i3j5BFEeI8aEK6VyJOJGbTYAZekygK7ptuE1xWcCikNcsXvQw5UrGYqi7lKwE4RuTg0SzRpShbUkkubxFhM9HM95EPgVSRdJIHVnd7BVuTaUsKCm7MFIojcwvRt7rgRekKp6hlrGhlm7YLnEY3pKQiCFjEqPT4B46Vd5DMDaAA7sGOJi0BfzKAP5rvKQwZXTlshVFBn6+VFblx9uSL0ijVQMQhtgXjF0OUOjqRoDjLhReywcR9jwxTa3CKFnFHhJLGZ1GGcWGJZVhT0zrd+qMvy1VTAxVQA8mApWugyqLI+bdjikXGDKNZone+Jz0pr2mV7PznpXerNf0ph3TU8dhP/ANwStzXcvqNb6ufdcyY9k+4evceYGBbx5CtiQ04uPdx2tMSRyJBV9sKGRfaXGp3XEoZDmGTgz6fBieCx9i1L4dW5ohz8xYvs6OQWvMGuROKPauxd2AML0Qpil2q6jQFrOnUvmTsLE3Y1m720qT21UyVYn52z+VK6Veorrvtqupfgd1wHMw6qIG1sEg9RFrcC4jT911HNDpEZ0pGUV8Y8Dr6g1JnSLlDHOCxbZx0GSckWYM+dJlt/KVhj7StDoQGGsD5WiMgXaGVaz7O2zNTBtPd9YMbLDc/Z1oc9OjHdNP61Lu1q44LDNT6Q07p2t2Zp7SG3bTjtmpyfrB7rXBM1OU/sDr2msVq17C6/q4sM30xIB3BBdMk/wXoiXeCsRt8uPZqAaw7o77nHGx3SSXuIi4WJnK8bhYjvgjLj5xXGw3ycFekreeepfTgBfb1xEnbS3htxskFK06qXUuJ5019FFlShfno47mo4ZRHfBRrnuYlZolokF6+I2BpR1Es9E330tvr31WwAv5G5x2wzB/9DPsngYkWqzSTjeMoXaq2zVh0XlP9QaZoPpSwM1CHHu7e9YjBBd5FPr7ohBA94u/i03/XDE+CmofNdBQz+w3zUJQFWidnDVoEL9fRgQ1abo5zy50c+46gAINsp3LcGsLdO/X/5vMaNrQr5X5/fDrl/v1JPsw28z/WPzzxN4H1+Svdw8PtOZzyxdb2ugZlvZyi1GB2au1BP3CqbEl6L+/z9oJv3WLM77SPdJeC9efG37z6v4L47z5/kNtcP8f&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 197.5 90 L 302.5 90 L 355 180 L 302.5 270 L 197.5 270 L 145 180 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="rotate(90,250,180)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 180px; margin-left: 161px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Trusted Service Provider<br />(application)</div></div></div></foreignObject><text x="250" y="184" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Trusted Service Provider...</text></switch></g><path d="M 157.5 25 L 342.5 25 L 435 185 L 342.5 345 L 157.5 345 L 65 185 Z" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="rotate(90,250,185)" pointer-events="all"/><rect x="230" y="305" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 315px; margin-left: 231px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Infrastructure</div></div></div></foreignObject><text x="250" y="319" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Infras...</text></switch></g><rect x="350" y="135" width="50" height="20" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 145px; margin-left: 351px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">adapter</div></div></div></foreignObject><text x="375" y="149" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="350" y="175" width="50" height="20" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 185px; margin-left: 351px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">adapter</div></div></div></foreignObject><text x="375" y="189" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="350" y="215" width="50" height="20" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 225px; margin-left: 351px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">adapter</div></div></div></foreignObject><text x="375" y="229" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="100" y="135" width="50" height="20" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 145px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">adapter</div></div></div></foreignObject><text x="125" y="149" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="100" y="175" width="50" height="20" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 185px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">adapter</div></div></div></foreignObject><text x="125" y="189" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="100" y="215" width="50" height="20" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 225px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">adapter</div></div></div></foreignObject><text x="125" y="229" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">adapter</text></switch></g><rect x="390" y="15" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 25px; margin-left: 391px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Platform/Environment</div></div></div></foreignObject><text x="410" y="29" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Platfo...</text></switch></g><ellipse cx="25" cy="145" rx="25" ry="15" fill="transparent" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 50 145 L 93.63 145" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 98.88 145 L 91.88 148.5 L 93.63 145 L 91.88 141.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="150" y="140" width="20" height="10" fill="#ffffff" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="150" y="180" width="20" height="10" fill="#ffffff" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="150" y="220" width="20" height="10" fill="#ffffff" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="330" y="220" width="20" height="10" fill="#ffffff" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="330" y="180" width="20" height="10" fill="#ffffff" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="330" y="140" width="20" height="10" fill="#ffffff" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="10" y="170" width="30" height="30" fill="#ffffff" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 40 185 L 93.63 185" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 98.88 185 L 91.88 188.5 L 93.63 185 L 91.88 181.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="375" cy="255" rx="15" ry="10" fill="#ffffff" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 400 225 L 430 225 Q 440 225 440 235 L 440 245 Q 440 255 430 255 L 396.37 255" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 391.12 255 L 398.12 251.5 L 396.37 255 L 398.12 258.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 125 240 L 140 255 L 125 270 L 110 255 Z" fill="#ffffff" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 450 134.5 C 450 125.17 470 125.17 470 134.5 L 470 155.5 C 470 164.83 450 164.83 450 155.5 Z" fill="#ffffff" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 450 134.5 C 450 141.5 470 141.5 470 134.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 400 145 L 443.63 145" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 448.88 145 L 441.88 148.5 L 443.63 145 L 441.88 141.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 450 174.5 C 450 165.17 470 165.17 470 174.5 L 470 195.5 C 470 204.83 450 204.83 450 195.5 Z" fill="#ffffff" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 450 174.5 C 450 181.5 470 181.5 470 174.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 400 185 L 443.63 185" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 448.88 185 L 441.88 188.5 L 443.63 185 L 441.88 181.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 110 255 L 60 255 Q 50 255 50 245 L 50 235 Q 50 225 60 225 L 93.63 225" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 98.88 225 L 91.88 228.5 L 93.63 225 L 91.88 221.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/developer/index.rst b/docs/developer/index.rst
index 33a03cc00..3204633e7 100644
--- a/docs/developer/index.rst
+++ b/docs/developer/index.rst
@@ -1,5 +1,5 @@
-Developer Docs
-==============
+Developer Documents
+===================
.. toctree::
:maxdepth: 1
@@ -7,20 +7,19 @@ Developer Docs
arch-overview
project-structure
- portability-model
+ service-deployment-model
service-access-protocols
service-locator
- deployments
- service-descriptions/index
software-requirements
build-instructions
running-tests
docs-build
writing-documentation
b-test
+ spmc-tests
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/portability-model.rst b/docs/developer/portability-model.rst
deleted file mode 100644
index 8305cb237..000000000
--- a/docs/developer/portability-model.rst
+++ /dev/null
@@ -1,211 +0,0 @@
-Portability Model
-=================
-
-Within the Trusted Services project, an environment represents the execution environment for an application such
-as a trusted service provider. Some example environments are:
-
- - *opteesp* - Secure partition managed by OP-TEE.
- - *opteeta* - TA running under OP-TEE with access to the Global Platform internal API.
- - *hfsp* - Secure partition managed by Hafnium.
-
-An underlying TEE or SPM that manages a secure processing environment will have its own model for porting to different hardware.
-For example, OP-TEE has its own driver model that allows for alternative hardware drivers. In some cases, a secure processing
-environment will not provide native support for all hardware that an application depends on. To address this, the TS
-portability model allows:
-
- - Application interfaces to be adapted to services natively provided by a secure processing environment if they are available.
- - Adapting to platform provided drivers when no native environment support is available.
-
-Ports and Adapters Architecture
--------------------------------
-
-An application is decoupled from any particular environment via a set of interfaces that reflect the needs of the application.
-This model conforms to the *ports and adapters* architectural pattern that aims to avoid tight coupling between application
-components and any particular environment. This pattern, also known as the *hexagonal architecture*, is often illustrated as
-a hexagonal cell with the application on the inside and the platform on the outside.
-
-The following diagram illustrates how ports and adapters is applied in the trusted services project to provide a model for
-application portability.
-
-.. image:: image/TSportabilityModel.svg
-
-The portability model has the following characteristics:
-
- - The application is decoupled from the environment by a set of virtual interfaces (ports) that reflect the needs of the
- application.
- - Those interfaces are realized by a set of adapters that either use native environment services or platform provided
- services.
- - For a given environment, the set of adapters that realize interfaces used by an application will always be the same,
- independent of the platform.
- - A platform presents interfaces that conform to conventional driver and middleware abstractions such as block drivers and
- filesystems.
- - The set of platform interfaces that an application depends on is defined by the set of adapters used for a deployment of an
- application in a particular environment. This can form the basis for a platform configuration.
-
-The need to use platform provided components will depend on the native features provided by an environment. For example, the
-*opteeta* environment represents the TA environment provided by OP-TEE. In its role as a trusted OS, OP-TEE provides access to
-an implementation of the Global Platform Internal Core API that provides services such as secure storage. Usage of any back-end
-hardware is handled by OP-TEE and its own OS components so no additional provision is needed. Bare metal environments such as
-secure partitions offer few native facilities so it may be necessary to map application interfaces to platform provided drivers.
-Mapping application interfaces to platform drivers is a way of extending the native services provided by an environment.
-
-The portability model allows for an arbitrary partitioning of hardware-backed services between native environment services and
-platform drivers.
-
-Portability Model Example
--------------------------
-
-To illustrate usage of the portability model, consider deployments of the following two trusted services:
-
- - fTPM based on the Microsoft TPM2.0 reference implementation.
- - trustedfirmware.org Crypto service based on the Mbed TLS library.
-
-The Microsoft TPM2.0 reference and Mbed TLS both define their own platform interfaces to allow for platform specific
-implementations of features such as roll-back protected storage and entropy. Although some interfaces are similar between the
-two implementations, they are not the same. These interfaces are classed as ports within the ports and adapters architecture.
-To simplify the example, just the entropy platform dependency is considered. Both fTPM and Crypto service providers need access
-to a cryptographic grade RNG to support key generation. How the RNG is realized will depend on:
-
- - What facilities the environment natively provides.
- - What other trusted services are available on the device.
- - Whether the environment allows for platform specific access to hardware.
- - Availability of a spare hardware TRNG instance.
-
-Adapters will be responsible for adapting both fTPM and Crypto views of an entropy source to a suitable realization.
-Some example adapters:
-
-fTPM adapters that realize MS entropy interface (port)
-''''''''''''''''''''''''''''''''''''''''''''''''''''''
- - *Adapts to crypto service* - Uses crypto service generate_random operation
- - *Adapts to TEE API* - Uses native TEE OS
- - *Adapts to TRNG* - Uses platform TRNG hardware
-
-Crypto adapters that realize Mbed TLS entropy source interface (port)
-'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
- - *Adapts to fTPM* - Uses TPM2 getrandom command
- - *TEE API* - Uses native TEE OS
- - *TRNG* - Uses platform TRNG hardware
-
-The above examples reveal that for a given environment, a port may be realized by more than one type of adapter. For example, an
-fTPM deployed within a secure partition could source entropy from either TRNG hardware or from the Crypto service. This
-ambiguity may be resolved by various strategies such as:
-
- 1. Allow a service profile to be applied at build time that defines a core set of mandatory trusted services. A build-time
- selection of alternative adapters is made, based on available core services.
- 2. A built image for a trusted service deployment to a particular environment includes the superset of adapters that could be
- used. A runtime configuration is applied, that specifies which adapters to use.
-
-Providing Platform Firmware
----------------------------
-
-A goal of the TS project is to reduce barriers to deploying trusted services on different hardware platforms. To this end,
-build-time and run-time coupling between TS project and platform components should be minimized. Platform providers should be
-free to make any of the following choices:
-
- - Reuse existing drivers and driver frameworks (e.g. from tf-a, an RTOS, CMSIS).
- - Provide platform components as part of a BSP.
- - Maintain platform components in separate repos.
- - Operate independent test, bug reporting and release processes for platform components.
- - Control the logical organization and naming of different platforms within the TS project.
- - Maintain whatever platform configuration files that are needed within the provider's sub-tree within the TS project.
-
-The platform top-level directory within the TS project provides a structure that allows platform specific components to be
-contributed by different providers. Different providers are represented beneath the platform/providers directory. The virtual
-platform interfaces used by some adapters are defined under platform/interface. The directory structure beneath a platform
-provider's parent is organized to reflect the provider's own naming scheme for different hardware. Supported platforms are each
-represented by a leaf sub-directory within the provider's subtree.
-
-For Arm provided platforms, the structure will look something like this::
-
- platform
- |-- interface
- |-- providers
- |--arm
- |-- corstone700
- |-- fvp
- |-- fvp_base_aemva
- |-- fvp_base_revc-2xaemv8a
- |-- platform.cmake
-
-Under each platform leaf directory is a file called *platform.cmake*. This file implements the common configuration and build
-interface that will be used during the deployment build process. How this interface is realized is entirely down to the
-platform provider. An implementation will do things like setting configuration variables for SoC, board and driver selection.
-Any additional files needed to support platform configuration and build may be included within the platform provider's sub-tree.
-
-For product developers who want to define and maintain their own private platforms, it should be possible to override the
-default platform/providers directory path to allow an alternative sub-tree to be used. A product developer is free to organize
-a private sub-tree in any way that suites their needs.
-
-Although the TS project structure doesn't mandate it, platform specific firmware is likely to live outside of the TS project.
-The ability to reuse existing drivers and driver frameworks is important for promoting adoption across hardware from different
-vendors. Board and silicon vendors may reuse existing CI and project infrastructure for platform components that they maintain.
-
-Some special platforms are provided by the TS project itself. These are represented beneath the *ts* provider.
-Current TS platforms are:
-
-.. list-table::
- :header-rows: 1
- :widths: 10, 90
-
- * - TS Platform
- - Purpose
- * - ts/vanilla
- - | A platform that never provides any drivers. The ts/vanilla platform should be used when an environment provides its own
- | device framework and no additional drivers need to be provided by the platform. An attempt to build a deployment with
- | platform dependencies on the vanilla platform will result in a build-time error. The vanilla platform is selected by
- | default at build-time if no explicit platform has been specified.
- * - ts/mock
- - | A platform that provides a complete set of drivers that may be selected when building any deployment. The platform uses
- | mock drivers that don't offer functionality suitable for production builds. The mock platform is useful for CI build
- | testing of deployments with platform dependencies. You should always expect a deployment with platform dependencies to
- | build when TS_PLATFORM=ts/mock.
-
-Determining a Platform Configuration for a Deployment
------------------------------------------------------
-
-The TS project supports building and installing an application image into different environments that could be hosted on
-different hardware platforms. A platform is characterized by SoC and board-level hardware and possibly by OS type components
-such as device drivers and middleware. To deploy an application that depends on platform drivers, you need to tie-down:
-
- - *Application name* - such as the name of the service e.g. crypto, secure-storage, attestation, tpm.
- - *Environment* - the environment in which the application will run e.g. bare metal secure partition, Global Platform TEE,
- Trusty TEE, microcontroller RTOS.
- - *Platform* - the hardware platform that hosts the environment.
-
-The following example illustrates how these parameters are specified via the deployment build command line::
-
- cd trusted-services/deployments/crypto/opteesp
- cmake -S . -B build -DTS_PLATFORM=arm/fvp/fvp_base_revc-2xaemv8a
-
-The combination of <application name> + <environment> allows a set of build-time platform dependencies to be generated, based on
-the set of adapter components used for the deployment. This information is passed via the platform build interface to the
-platform.cmake file for the specified platform via a CMake target property called TS_PLATFORM_DRIVER_DEPENDENCIES. The
-translation of the platform dependency information to a suitable build configuration is handled by the platform.cmake file for
-the selected platform. This separation gives a platform provider the freedom to use their own configuration conventions when
-reusing existing drivers.
-
-To allow for out-of-tree platform definitions, the root path for platform definitions may be modified by providing an
-alternative value for TS_PLATFORM_ROOT. Both TS_PLATFORM and TS_PLATFORM_ROOT may be set via the CMake command line or using
-environment variables.
-
-Adapters
---------
-
-As described above, the role of an adapter conforms to the Ports and Adapters pattern. With reference to the hexagonal cell
-representation, an adapter implements an application defined inside interface and adapts it to either an environment interface
-or an outside platform interface. Within the TS project, adapters are treated like any other software component and may be
-reused whenever appropriate. However, because an adapter implements an application defined interface, adapter implementations
-will tend to be tied to a particular application or component. The complexity of adapter implementations can vary a lot and
-will depend on how closely an inside interface matches either an outside interface or an environment interface.
-
-The collection of adapters used for a deployment is defined by the environment specific build file for a deployment. Deployment
-of the same service into a different environment may result in a different set of adapters being used. As each adapter is
-treated as a separate component, a separate component.cmake file exists for each adapter. When an adapter depends on one or
-more platform interfaces, the dependency must be declared in the adapter's component.cmake file. This information forms the
-basis for the platform build configuration.
-
---------------
-
-*Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.*
-
-SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/project-structure.rst b/docs/developer/project-structure.rst
index b69af9850..0e34989fe 100644
--- a/docs/developer/project-structure.rst
+++ b/docs/developer/project-structure.rst
@@ -40,6 +40,7 @@ deployments::
deployments
|-- protected-storage/opteesp
|-- crypto/opteesp
+ |-- crypto/sp
|-- ts-demo/arm-linux
|-- component-test/linux-pc
|-- libts/linux-pc
@@ -61,6 +62,9 @@ under the deployment parent. This is illustrated in the following::
|-- common.cmake <-- Common cmake file
|-- service_init.c <-- Common initialization code
|-- opteesp
+ | |-- CMakeLists.txt <-- Includes ../common.cmake to inherit common definitions
+ | |-- opteesp_service_init.c
+ |-- sp
|-- CMakeLists.txt <-- Includes ../common.cmake to inherit common definitions
|-- opteesp_service_init.c
@@ -72,6 +76,7 @@ represented in the project structure, one for each supported isolated execution
particular environment live under a sub-directory whose name describes the environment. For example:
- *opteesp* An S-EL0 secure partition hosted by OP-TEE
+ - *sp* SPMC agnostic S-EL0 secure partition
- *arm-linux* Linux user-space, cross compiled for Arm.
- *linux-pc* Native PC POSIX environment
@@ -87,13 +92,33 @@ following:
A deployment will include an environment specific build file (see above) that defines the list of environment
specific components used for a deployment into a particular environment.
+opteesp
+"""""""
+
+The opteesp environment uses a very similar SP format to the OP-TEE Trusted Applications. It is an ELF file with an OP-TEE
+specific header structure at its beginning. The SP image is relocatable and it is handled by the ELF loader (ldelf) component
+of OP-TEE. Naturally this environment only works with OP-TEE in the role of the SPMC.
+
+sp
+""
+
+Deployments that use the sp environment can produce SPMC agnostic SP images. This environment generates SP images as flat
+binaries that can be loaded without an ELF loader. The initialization of the stack and the handling of relocation must be done
+in the startup code of the SP. Setting the memory access rights of different sections of the SP image can be either done
+thought load relative memory regions in the manifest or by using the ``FFA_MEM_PERM_SET`` interface of the FF-A v1.1
+specification in the boot phase of the SP.
+
+Trusted Services first builds ELF files for the sp environment deployments and then it generates the memory region nodes of the
+manifest based on the sections of the ELF file. The sections of the ELF is then copied into the flat binary image. The
+environment provides the startup file so all the necessary initialization steps are done before the ``sp_main`` call.
+
platforms
'''''''''
For some deployments, an environment may not provide access to all hardware backed services needed by an
application. Files under the platforms directory are concerned with configuring and building platform specific
code that extends the capabilities of an environment. Details of how this works are described in the:
-:ref:`Portability Model`
+:ref:`Service Deployment Model`
components
''''''''''
@@ -206,6 +231,6 @@ to support activities such as build and test.
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/service-access-protocols.rst b/docs/developer/service-access-protocols.rst
index 4161f0d15..8a8c8a448 100644
--- a/docs/developer/service-access-protocols.rst
+++ b/docs/developer/service-access-protocols.rst
@@ -10,42 +10,254 @@ schemes to suite different needs. The project accommodates this with the follow
- Message serialization code is decoupled from service provider code using an abstract 'serializer' interface. Alternative
concrete serializers may provide implementations of the interface.
-RPC Session
------------
+A deployment independent interface for locating services and establishing RPC sessions is described here: :ref:`Service Locator`
+
+Trusted Services protocol layers
+--------------------------------
+
+.. image:: image/TSProtocolLayers.svg
+
+* Service client interface: This component provides the interface to a given service for a user application, i.e. the PSA
+ Crypto, Internal Trusted Storage, etc. interface.
+
+* Service layer: This layer is responsible for serializing and deserializing the service specific parameters and it provides
+ a transparent interface between the caller and endpoint side.
+
+* RPC layer:
+
+ * RPC caller session: This component provides a session-like object for the service layer. After opening the session, it is
+ tied to the opened service interface of the endpoint. Each service call can use the simple begin/invoke/end interface for
+ requesting a buffer for the call parameters, for invoking the call and for releasing the response buffer.
+
+ The RPC caller session manages the lifetime of the shared memory. Currently it has two options. It either creates the
+ memory on session open and keeps it while the session is open, or it creates the shared buffer for each call and releases
+ it when the call ends (``end()``).
+
+ * RPC caller implementations (`ts_rpc_caller_linux`, `ts_rpc_caller_sp`, etc.): The RPC caller session is built on the
+ primitives of the RPC callers. These primitives allow the caller session finding the remote endpoint, creating and
+ releasing shared memories and doing the actual call.
+
+ The main RPC implementation is the TS RPC which is a TS specific RPC solution over FF-A. The project contains caller
+ implementations for Linux and for S-EL0 SPs. The Linux implementation is split between the user space and a kernel driver.
+
+ There are other RPC caller implementations (dummy, direct) which are used for testing purposes.
+
+ * RPC endpoint (`ts_rpc_endpoint_sp`): This component provides the RPC endpoint which can host multiple services. Once it
+ receives the call from the client, it finds the matching service and forwards the serialized call parameters to it.
+
+* FF-A layer: It is the transport layer of the protocol stack, and it provides interfaces for sending messages and sharing
+ memory between normal world and secure world components.
+
+TS RPC implementation
+---------------------
+
+Generic concepts
+''''''''''''''''
+
+* The requests are always sent by the caller and the endpoint sends a response.
+* The protocol version describes the ABI, the allowed values of the message fields and the behavior of the calls.
+* Service endpoints are provided by FF-A secure partitions.
+* Each endpoint can implement multiple services. The services are identified by their service UUID (**not** FF-A UUID). To
+ avoid including the UUID in each service call, a short interface ID is assigned to each service. The mapping of service
+ UUIDs and interface IDs can be queried by an RPC call. The lifetime of the interface ID is the same as the lifetime of the
+ service. The `0xff` interface ID is used for the management interface.
+* The service calls use shared memory to forward the call payload. It has to be shared via FF-A and then retrieved by the
+ endpoint. The shared memories are tied to an endpoint not to a service.
+* The errors which happen in the RPC layer will result in a RPC status code which indicates an error.
+* The errors which happen in the service handler will result in a service status code which indicates an error. In this case
+ the RPC status code will be `RPC_SUCCESS` as the RPC layer was able to forward the call between the service caller and the
+ service handler.
+
+ABI
+'''
+
+The ABI of the TS RPC protocol uses the 32 bit variants of ``FFA_MSG_SEND_DIRECT_REQ`` and ``FFA_MSG_SEND_DIRECT_RESP``
+interfaces of the FF-A specification. The use of the implementation specific arguments is listed in the table below.
+
+.. list-table:: TS RPC ABI
+ :header-rows: 1
+
+ * - Message name
+ - Short message ID
+ - W3[31:30] - SAP
+ - W3[29:24] - Flags
+ - W3[23:16] - Interface ID
+ - W3[15:0] - Opcode
+ - W4 - Arg1
+ - W5 - Arg2
+ - W6 - Arg3
+ - W7 - Arg4
+ * - RPC protocol version get request
+ - ``VERSION_GET``
+ - ``0b00``
+ - ``0b000000``
+ - ``0xff``
+ - ``0x0000``
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ * - RPC protocol version get response
+ - ``VERSION_GET``
+ - ``0b00``
+ - ``0b000000``
+ - ``0xff``
+ - ``0x0000``
+ - Version, starting from ``0x00000001``
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ * - Memory retrieve request
+ - ``MEM_RETRIEVE``
+ - ``0b00``
+ - ``0b000000``
+ - ``0xff``
+ - ``0x0001``
+ - FF-A memory handle LSW
+ - FF-A memory handle MSW
+ - FF-A memory tag LSW
+ - FF-A memory tag MSW
+ * - Memory relinquish request
+ - ``MEM_RELINQUISH``
+ - ``0b00``
+ - ``0b000000``
+ - ``0xff``
+ - ``0x0002``
+ - FF-A memory handle LSW
+ - FF-A memory handle MSW
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ * - Memory retrieve/relinquish response
+ - ``MEM_RETRIEVE``/``MEM_RELINQUISH``
+ - ``0b00``
+ - ``0b000000``
+ - ``0xff``
+ - ``0x0001``/``0x0002``
+ - TS RPC status
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ * - Service info get request
+ - ``SERVICE_INFO_GET``
+ - ``0b00``
+ - ``0b000000``
+ - ``0xff``
+ - ``0x0003``
+ - Service UUID
+ - Service UUID
+ - Service UUID
+ - Service UUID
+ * - Service info get response
+ - ``SERVICE_INFO_GET``
+ - ``0b00``
+ - ``0b000000``
+ - ``0xff``
+ - ``0x0003``
+ - TS RPC status
+ - ``[31:8]`` Reserved
+
+ ``[7:0]`` Queried service interface ID
+ - Reserved (MBZ)
+ - Reserved (MBZ)
+ * - Service call request
+ -
+ - ``0b00``
+ - ``0b000000``
+ - Service interface ID
+ - Service opcode
+ - FF-A memory handle LSW
+ - FF-A memory handle MSW
+ - Request length
+ - Client ID
+ * - Service call response
+ -
+ - ``0b00``
+ - ``0b000000``
+ - Service interface ID
+ - Service opcode
+ - TS RPC status
+ - Service status
+ - Response length
+ - Reserved
+
+* **RPC protocol version get**
+
+ Queries the RPC protocol version. This message must be available and backwards compatible for all protocol versions.
+
+* **Memory retrieve**
+
+ Requests the endpoint to do an ``FFA_MEM_RETRIEVE_REQ`` call using the forwarded FF-A memory handle and tag.
+
+* **Memory relinquish**
+
+ Requests the endpoint to do an ``FFA_MEM_RELINQUISH`` call using the forwarded FF-A memory handle.
+
+* **Service info get**
+
+ Query service information from the endpoint by the UUID of the service. The UUID is transmitted as defined in SMCCC section
+ 5.3 but in registers W4-W7. The returned service interface ID should be used in the service calls. Multiple endpoints can
+ implement the same service but one endpoint can implement a service only once.
+
+* **Service call**
+
+ After creating a shared memory and querying the interface ID for a given service UUID the caller can make a service call. The
+ service opcode and the contents of the shared memory is service specific. The request and response length fields indicate the
+ used area of the shared memory.
+
+ It is allowed to do a limited service call without shared memory, i.e. doorbell call. In this case the FF-A memory ID has to
+ be the invalid handle value ``0xffffffffffffffff``.
+
+Service discovery
+'''''''''''''''''
-Before a client can call trusted service methods, an RPC session must be established where an association is made between an RPC
-Caller and a call endpoint that corresponds to the required service provider instance. To establish the session, the client
-must provide:
+* Query all TS SPs via ``FFA_PARTITION_INFO_GET`` call made to the SPMC. All TS SPs have the same FF-A UUID:
+ ``bdcd76d7-825e-4751-963b-86d4f84943ac`` If the system setup has fixed SP endpoint IDs, this step can be skipped.
+* Iterate thought the TS SPs and make a "Service info get request" RPC call to the SPs, containing the service UUID. If the
+ RPC status in the "Service info get response" is `RPC_SUCCESS`, the SP implements the service and its interface ID is returned
+ in the response.
+* If there are multiple instances of a service, the selection between these should be done in a service specific way (i.e.
+ query service version, capabilities, etc.).
- - An identifier for the service provider instance.
- - Any client credentials that allow RPC layer access control to be applied if needed.
+.. image:: image/TSServiceDiscovery.svg
-.. uml:: uml/RpcSessionClassDiagram.puml
+RPC status code values
+'''''''''''''''''''''''
-Once the RPC session is established, the client may call service methods via an abstract RPC Caller interface that takes the
-following parameters:
+The status codes for the RPC layer are defined in `components/rpc/common/interface/rpc_status.h`. Currently the following values
+are defined:
- - The opcode that identifies the method to call.
- - A buffer for the serialized method parameters.
- - A buffer for the serialized return values.
+.. literalinclude:: ../../components/rpc/common/interface/rpc_status.h
+ :lines: 20-32
+ :language: C
-A deployment independent interface for locating services and establishing RPC sessions is described here: :ref:`Service Locator`
+Example TS RPC call
+'''''''''''''''''''
+
+This example shows the full sequence of a service call by opening the RPC session, doing the call (begin/invoke/end) and then
+closing the session. In this case the RPC session it set to create individual shared memory for each call.
+
+.. uml:: uml/TSRPCCall.puml
+
+.. note::
+ Although the TS RPC layer messages use ``FFA_MSG_SEND_DIRECT_REQ``/``FFA_MSG_SEND_DIRECT_RESP`` interface and go through the
+ SPMC their destination is not the SPMC but the RPC endpoint. For simplifying the diagram, these calls are showed as direct
+ calls between the TS RPC caller and the TS RPC endpoint.
Status Codes
------------
-On returning from a request to invoke a service method, two status codes are returned as follows:
+On returning from a request to invoke a service method, two status codes are returned:
- *RPC status* - A generic status code that corresponds to the RPC call transaction. RPC status codes are standardized across
- all services.
- - *Operation status* - a service specific status code.
+ all services. (See: `RPC status code values`_)
+ - *Service status* - a service specific status code. (See: `Service Status Codes`_ )
Separation of status codes by layer allows service specific status codes to be accommodated while keeping RPC status codes
common.
-A client should only check the returned operation status if the returned RPC status value is RPC_CALL_ACCEPTED. All other RPC
-status values indicate that an error occurred in delivering the RPC request. An RPC status of RPC_CALL_ACCEPTED does not
-indicate that the service operation was successful. It merely indicates that the request was delivered, a suitable handler was
+A client should only check the returned service status if the returned RPC status value is `RPC_SUCCESS`. All other RPC
+status values indicate that an error occurred in delivering the RPC request. An RPC status of `RPC_SUCCESS` does not
+indicate that the service was successful. It merely indicates that the request was delivered, a suitable handler was
identified and the request parameters were understood.
Service Access Protocol Definition Conventions
@@ -62,7 +274,7 @@ Details of how public interface definition files for trusted services are organi
It is possible that for certain deployments, it will be necessary to customize which parameter encoding scheme is used. Many
schemes are possible such as Protocol Buffers, CBOR, JSON, TLV, TPM commands or packed C structures. To make scheme
-customization straight forward, serilize/deserialize operations should be encapsulated behind a common interface to decouple
+customization straight forward, serialize/deserialize operations should be encapsulated behind a common interface to decouple
service provider code from any particular serialization scheme. A section below describes a pattern for achieving this.
Service Namespace
@@ -122,14 +334,6 @@ For example, the Crypto export_public_key method is defined in a file called::
protocols/service/crypto/protobuf/export_public_key.proto
-RPC Status Codes
-````````````````
-
-Generic RPC status code definitions using different definition schemes are defined here::
-
- protocols/rpc/common/protobuf/status.proto
- protocols/rpc/common/packed-c/status.h
-
Service Status Codes
````````````````````
@@ -182,21 +386,11 @@ operations will have the following pattern::
int serialize_for_method(msg_buffer *buf, in args...);
int deserialize_for_method(const msg_buffer *buf, out args...);
-To extend a service provider to support a new serialization encoding, the following steps are required:
-
- 1. Define a new encoding identifier string if a suitable one doesn't exist. Currently used identifiers are protobuf and
- packed-c. The identifier will be used as a directory name so it needs to be filename-friendly. Some likely candidate
- identifiers could be cbor and json.
- 2. Add a new RPC encoding ID to *protocols/rpc/common/packed-c/encoding.h*. This is used by a caller to identify the encoding
- used for RPC parameters. This is analogous to the content-type header parameter used in HTTP.
- 3. Under the protocols parent directory, add a new access protocol definition for the service that needs extending. This will
- be a representation of existing service access protocols but using a definition notation compatible with the new encoding.
- 4. Add a new serializer implementation under the service provider's serializer directory e.g. for the crypto service -
- *components/service/crypto/provider/serializer*.
- 5. Add registration of the new serializer to any deployment initialization code where the new encoding is needed.
+Encoding types are represented as dedicated service interfaces in the RPC protocol and as such are identified by a uniq
+service UUID.
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/service-deployment-model.rst b/docs/developer/service-deployment-model.rst
new file mode 100644
index 000000000..9f7999931
--- /dev/null
+++ b/docs/developer/service-deployment-model.rst
@@ -0,0 +1,292 @@
+Service Deployment Model
+========================
+A goal of the Trusted Services project is to provide a toolbox of reusable service components
+that can be deployed across a wide range of platforms. The project structure promotes reuse by
+grouping related source files into subdirectories that represent reusable components. Components
+may be configured and combined in different ways to meet the needs of platform integrators who
+aim to create firmware with the right features and tradeoffs for their products.
+
+Within the TS project structure, build files that combine and configure components to create
+deployable firmware images reside under the deployments top-level directory. Beneath the
+deployments parent are sub-directories concerned with building and deploying different
+applications. Applications can generally be classified as one of the following:
+
+ - Service providers
+ - Test suites
+ - Libraries
+ - Development support applications
+
+This page is mainly concerned with describing the conventions used to enable service providers
+to be deployed in different environments, on different platforms and with different capabilities.
+The conventions aim to minimize build definition duplication between alternative deployments
+while offering sufficient flexibility to customize capabilities and support different platforms.
+The service deployment model borrows from a pattern used for deploying cloud services where There
+is a similar requirement for deployment flexibility.
+
+Ports and Adapters Architecture
+-------------------------------
+An application is decoupled from any particular environment via a set of interfaces that reflect
+the needs of the application. This model conforms to the ports and adapters architectural
+pattern that aims to avoid tight coupling between application components and any particular
+environment. This pattern, also known as the hexagonal architecture, is often illustrated as a
+hexagonal cell with the application on the inside and the platform on the outside.
+
+The following diagram illustrates how ports and adapters is applied in the trusted services
+project to provide a model for service provider deployment.
+
+.. image:: image/TSportabilityModel.svg
+
+This deployment model has the following characteristics:
+
+ - The application is decoupled from the environment by a set of virtual interfaces (ports)
+ that reflect the needs of the application.
+ - Ports are realized by a set of adapters. An adapter may:
+
+ * Use a service/device provided by the platform or environment.
+ * Communicate with another service provider.
+ * Provide a self-contained implementation.
+ - The set of adapters that the application depends on represents the infrastructure that is
+ needed to support the application.
+ - Different infrastructure realizations may be needed for different deployments of the same
+ service provider.
+
+Service Deployment Structure
+----------------------------
+By convention, the directory structure for service provider deployments reflects the layers in
+the ports and adapters architecture. The following dependency diagram illustrates the set of
+relationships that exist for a fully defined deployment:
+
+.. uml:: uml/ServiceDeploymentDependencies.puml
+
+To avoid undesirable build definition duplication when adding new deployments of an application,
+the directory structure used to organize files related to different deployments should reflect
+the above model. The following table lists reusable build components that may be used across
+different deployment definitions:
+
+.. list-table::
+ :widths: 10 20 20
+ :header-rows: 1
+
+ * - Build Component
+ - Defines
+ - Reuse Scope
+ * - Application
+ - | Set of components that form the core application to be deployed.
+ - | All deployments of the application.
+ * - Infra
+ - | The set of adapters that realize the ports that the application depends on.
+ | An infrastructure definition may depend on:
+
+ * Environment specific components.
+ * Drivers that conform to a driver model.
+ * Platform specific drivers.
+ - | Any deployment that uses the same infrastructure to support the application.
+ | This will depend on how specific the infrastructure is. An infrastructure
+ | definition may allow for some level of configurability to enable deployment
+ | to impose a particular build configuration. Where an infrastructure includes
+ | adapters that use a well supported driver model (such as UEFI), the scope
+ | for reuse is large.
+ * - Env
+ - | The set of environment specific components that are common across all
+ | deployments of an application for a particular environment.
+ - | All deployments of the application into a specific environment. There is
+ | scope to improve reuse of environment specific components across multiple
+ | deployments.
+ * - Config
+ - | Build configuration variables together with a particular application, infra
+ | and env.
+ - | Depends on how specific the config is.
+
+Deployment Directory Structure
+------------------------------
+Using the block-storage deployment as an example, the deployment directory structure reflects
+the service deployment model as follows::
+
+ deployments
+ |- block-storage
+ |- block-storage.cmake - Common application build definition
+ |- env - Environment specific build definitions
+ |- infra - Alternative infrastructures
+ |- config - Configurations for block-storage deployments
+
+Configuration Definitions
+^^^^^^^^^^^^^^^^^^^^^^^^^
+To build a particular configuration of the block-storage service provider (in this case, one
+that uses flash storage on the N1SDP platform), use::
+
+ cd deployments/block-storage/config/n1sdp-flash
+ cmake -B build
+ cd build
+ make
+
+The CMakeLists.txt file for the n1sdp-flash deployment of the block-storage service provider
+includes:
+
+ - Set TS_PLATFORM to n1sdp platform name
+ - Set any build configuration parameter overrides
+ - Include ``${DEPLOYMENT_ROOT}/env/opteesp.cmake``
+ - Include ``${DEPLOYMENT_ROOT}/infra/edk2-flash.cmake``
+ - Include ``${DEPLOYMENT_ROOT}/block-storage.cmake``
+
+Each alternative deployment of the block-storage service provider is represented by a
+subdirectory under ``${DEPLOYMENT_ROOT}/config``. The number of directories under config is
+likely to grow to accommodate platform variability and different tradeoffs for how the infrastructure
+for an application will be realized.
+
+To support test and to provide a starting point for new config definitions, a default config should
+exist for each supported environment.
+
+Infrastructure Definitions
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+An infrastructure defines a set of adapter components that realize the ports that the application
+depends on. For block-storage deployments, some possible infrastructures are:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 10, 40
+
+ * - Infra Name
+ - Description
+ * - ref-ram
+ - Provides volatile storage using the reference partition configuration. Intended for test.
+ * - edk2-flash
+ - Provides persistent storage using a flash driver that conforms to the EDK2 driver model.
+ * - tfa-flash
+ - Provides persistent storage using a flash driver that conforms to the TF-A driver model.
+ * - rpmb
+ - Provides persistent storage using an RPMB partition, accessed via a Nwd agent.
+
+Platform Support
+----------------
+The Trusted Services project is not intended to be a home for platform specific code such as
+device drivers. Ideally, device drivers and other platform specific code should be reused
+from external upstream repos such as edk2-platforms. The ports and adapters pattern allows
+alternative driver models to be accommodated so different upstream projects with different
+driver models may be used without the need to modify driver code. Where driver reuse from
+an external project is not possible, the platform directory structure can accommodate driver
+components that reside within the TS project.
+
+The ability to accommodate third-party device drivers that conform to different driver models
+is important for enabling TS components to be used across different segments. The EDK2
+project for example can provide a rich source of drivers that conform to the UEFI model.
+UEFI is not however adopted in all product segments.
+
+All files related to supporting different platforms reside beneath the platform top-level
+directory.
+
+Platform Providers
+^^^^^^^^^^^^^^^^^^
+Within the TS project, a platform provider is responsible for adding and maintaining the
+glue that enables platform specific code to be used from a particular source. The platform
+code will either be:
+
+ - Fetched from an upstream repo (preferred)
+ - Added to the TS project.
+
+Each platform provider is represented by a subdirectory beneath ``platform/providers``. For
+Arm provided platforms, the structure will look something like this::
+
+ platform
+ |-- providers
+ |--arm
+ |-- corstone1000
+ |-- fvp
+ |-- fvp_base_aemva
+ |-- fvp_base_revc-2xaemv8a
+ |-- platform.cmake
+
+Under each platform leaf directory is a file called ``platform.cmake``. This file implements
+the common configuration and build interface that will be used during the deployment build
+process. How this interface is realized is entirely down to the platform provider. An
+implementation will do things like setting configuration variables for SoC, board and driver
+selection. Any additional files needed to support platform configuration and build may be
+included within the platform provider's sub-tree.
+
+For product developers who want to define and maintain their own private platforms, it should
+be possible to override the default ``platform/providers`` directory path to allow an
+alternative sub-tree to be used. A product developer is free to organize a private sub-tree
+in any way that suites their needs.
+
+Although the TS project structure doesn't mandate it, platform specific firmware is likely
+to live outside of the TS project. The ability to reuse existing drivers and driver frameworks
+is important for promoting adoption across hardware from different vendors. Board and silicon
+vendors may reuse existing CI and project infrastructure for platform components that they
+maintain.
+
+Platform support that depends on EDK2 platform components is represented by the edk2 platform
+provider. Files related to the EDK2 platform provider are organized as follows::
+
+ platform
+ |- providers
+ |- edk2
+ |- edk2-platforms.cmake - Fetches the upstream edk2-platforms repo
+ |- platform - Directory for platform definitions, organized by contributor
+ |- arm
+ |- n1sdp
+ |- platform.cmake
+
+Some special platforms are provided by the TS project itself. These are represented beneath
+the ts provider. Current TS platforms are:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 10, 90
+
+ * - TS Platform
+ - Purpose
+ * - ``ts/vanilla``
+ - | A platform that never provides any drivers. The ``ts/vanilla`` platform should be used when an environment provides its own
+ | device framework and no additional drivers need to be provided by the platform. An attempt to build a deployment with
+ | platform dependencies on the vanilla platform will result in a build-time error. The vanilla platform is selected by
+ | default at build-time if no explicit platform has been specified.
+ * - ``ts/mock``
+ - | A platform that provides a complete set of drivers that may be selected when building any deployment. The platform uses
+ | mock drivers that don't offer functionality suitable for production builds. The mock platform is useful for CI build
+ | testing of deployments with platform dependencies. You should always expect a deployment with platform dependencies to
+ | build when ``TS_PLATFORM=ts/mock``.
+
+Diver Models
+^^^^^^^^^^^^
+Alternative driver models are represented by subdirectories beneath ``platform/driver_model``.
+Driver code imported from an external project, such as edk2-platforms, will also depend on
+interface and other header files related to the driver model. For drivers reused from
+edk2-platforms, the driver interface header files will define interface structures defined
+by the UEFI specification. The following example illustrates two driver models, one for
+UEFI drivers from the EDK2 project and another for bare-metal drivers that conform to TS
+defined interfaces::
+
+ platform
+ |- driver_model
+ |- edk2
+ |- baremetal
+
+Header files under the driver_model/edk2 directory will either explicitly provide definitions for
+the EDK2 driver model or include definitions from an external component. To maintain compatibility
+with driver code imported from edk2-platforms, sub-directories beneath platform/driver_model/edk2
+should conform to the EDK2 directory structure and naming conventions. The following illustrates
+how UEFI driver model files are organized::
+
+ platform
+ |- driver_model
+ |- edk2
+ |- interface
+ |- Protocol
+ | |- BlockIo.h
+ | |- DiskIo.h
+ | |- FirmwareVolumeBlock.h
+ |
+ |- Library
+ | |- IoLib.h
+ | |- DebugLib.h
+
+Drivers
+^^^^^^^
+The platforms/drivers directory provides a home for CMake files that enable driver code to be built
+as part of the the deployment build process. Source files will either have been fetched from an
+upstream repo or will live under the ``platform/drivers`` parent.
+
+--------------
+
+*Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/software-requirements.rst b/docs/developer/software-requirements.rst
index 700c32da6..cbdf81aba 100644
--- a/docs/developer/software-requirements.rst
+++ b/docs/developer/software-requirements.rst
@@ -16,23 +16,24 @@ The following tools are required:
* Python3.6 and the modules listed in ``<project>/requirements.txt``.
* GCC supporting the deployment.
- * `opteesp` environment: a host to aarch64 cross-compiler is needed. Please use the compilers specified by the
+ * `opteesp` and `sp` environments: a host to aarch64 cross-compiler is needed. Please use the compilers specified by the
`OP-TEE documentation`_.
* `arm-linux` environment: a host to aarch64 linux cross-compiler is needed. Please use the version `9.2-2019.12` of the
"aarch64-none-linux-gnu" compiler available from `arm Developer`_.
(Note: the compiler part of the OP-TEE build environment works too.)
* For `linux-pc` environment use the native version of GCC available in your Linux distribution.
-To build the documentation, please refer to :ref:`Documentation Build Instructions`.
+ * The `AEM FVP`_ binaries if targeting the FVP platform.
-.. todo:: Add info on commit validation dependencies (checkpatch, uncrustify, etc...)
+To build the documentation, please refer to :ref:`Documentation Build Instructions`.
--------------
.. _OP-TEE documentation: https://optee.readthedocs.io/en/latest/building/gits/build.html#step-4-get-the-toolchains
.. _arm Developer: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads
.. _CMake download page: https://cmake.org/files/v3.18/
+.. _`AEM FVP`: https://developer.arm.com/-/media/Files/downloads/ecosystem-models/FVP_Base_RevC-2xAEMvA_11.18_16_Linux64.tgz
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/spmc-tests.rst b/docs/developer/spmc-tests.rst
new file mode 100644
index 000000000..a61077f5e
--- /dev/null
+++ b/docs/developer/spmc-tests.rst
@@ -0,0 +1,180 @@
+OP-TEE SPMC tests
+=================
+
+Build and run
+-------------
+
+Please follow the instructions of :ref:`build-spmc-tests`.
+
+Structure
+---------
+
+* `xtest`_ is the |NWd| test application which is used to send multiple |FF-A| messages to the SPMC and to the test SPs in
+ the |SWd|. It is part of the `optee_test`_ repository.
+* The ``arm-ffa-user`` driver provides access to the FF-A layer from the |NWd| user space. ``xtest`` uses it to send |FF-A|
+ messages.
+* The test SPs implement various testing functions which can be invoked from ``xtest``.
+
+.. uml:: uml/SpmcTestStructure.puml
+
+Implementation
+--------------
+
+* |TS|
+ * ``components/service/spm_test`` implements the common code of the test SPs.
+ * ``deployments/spm-test*`` are the test SP deployments. There are currently four test SPs to cover various test
+ scenarios. SPM test SPs use |FF-A| v1.1 except SPM test SP 2 which uses v1.0 to cover the backwards compatibility test
+ of the SPMC.
+* `optee_test`_
+ * `ffa_spmc_1000.c`_ contains the SPMC test cases of ``xtest``.
+
+SPMC test RPC protocol
+----------------------
+
+Tests can invoke the functions of the test SPs via an SPMC test specific RPC interface which is built on top of FF-A direct
+messages.
+
+.. list-table:: Test RPC protocol
+ :header-rows: 1
+
+ * - Message ID
+ - Description
+ - ``args[0]``
+ - ``args[1]``
+ - ``args[2]``
+ - ``args[3]``
+ - ``args[4]``
+ * - EP_TEST_SP
+ - Run internal SP tests
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_TEST_SP_COMMUNICATION
+ - Test FF-A direct message request
+ - ``0x00000001``
+ - The destination SP's FF-A endpoint ID
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_TEST_SP_INCREASE
+ - Increase each ``param`` value by one and return response
+ - ``0x00000002``
+ - ``param[0]``
+ - ``param[1]``
+ - ``param[2]``
+ - ``param[3]``
+ * - EP_TRY_R_ACCESS
+ - Test shared buffer read access
+ - ``0x00000003``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_TRY_W_ACCESS
+ - Test shared buffer write access
+ - ``0x00000004``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_RETRIEVE
+ - Do FF-A memory retrieve
+ - ``0x00000005``
+ - Memory handle LSW
+ - Memory handle MSW
+ - Sender endpoint ID
+ - ``0x00000000``
+ * - EP_RELINQUISH
+ - Do FF-A memory relinquish
+ - ``0x00000006``
+ - Memory handle LSW
+ - Memory handle MSW
+ - Flags
+ - ``0x00000000``
+ * - EP_SP_MEM_SHARING
+ - Test FF-A memory sharing
+ - ``0x00000007``
+ - Target endpoint's FF-A ID
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_SP_MEM_SHARING_MULTI
+ - Test FF-A memory sharing with multiple endpoints
+ - ``0x00000008``
+ - Target endpoint 1 FF-A ID
+ - Target endpoint 2 FF-A ID
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_SP_MEM_SHARING_EXC
+ - Test exclusive FF-A memory sharing
+ - ``0x00000009``
+ - Target endpoint's FF-A ID
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_SP_MEM_INCORRECT_ACCESS
+ - Negative FF-A memory sharing test
+ - ``0x0000000a``
+ - Target endpoint's FF-A ID
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_SP_NOP
+ - No operation
+ - ``0x0000000b``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - EP_TEST_SP_COMMUNICATION_RESPONSE
+ - Test FF-A direct message response
+ - ``0x0000000c``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+ * - SP_TEST_OK
+ - Successful test response
+ - ``0x000000aa``
+ - Request specific parameter
+ - Request specific parameter
+ - Request specific parameter
+ - Request specific parameter
+ * - SP_TEST_ERROR
+ - Error test response
+ - ``0x000000ff``
+ - Error code
+ - ``0x00000000``
+ - ``0x00000000``
+ - ``0x00000000``
+
+Test cases
+----------
+
+The following test cases are defined in ``ffa_spmc_1000.c``:
+
+* 1001: Test basic FF-A communication
+ * Try to connect to multiple SPs
+ * Have different SPs sending messages to each other
+ * Test standard SP messages (partition_info_get, get_own_id, ...)
+* 1002: Test FF-A memory
+ * Test memory sharing between the |NWd| and the |SWd|
+* 1003: Test FF-A memory: SP to SP
+ * Test memory sharing between to SPs
+* 1004: Test FF-A memory: Access and flags
+ * Test the different access modifiers and flags when sharing memory
+* 1005: Test FF-A memory: multiple receiver
+ * Share a memory region with multiple SPs
+
+--------------
+
+.. _`xtest`: https://optee.readthedocs.io/en/latest/building/gits/optee_test.html
+.. _`optee_test`: https://github.com/OP-TEE/optee_test
+.. _`ffa_spmc_1000.c`: https://github.com/OP-TEE/optee_test/blob/master/host/xtest/ffa_spmc_1000.c
+
+
+*Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/docs/developer/uml/ServiceDeploymentDependencies.puml b/docs/developer/uml/ServiceDeploymentDependencies.puml
new file mode 100644
index 000000000..515a7c5c7
--- /dev/null
+++ b/docs/developer/uml/ServiceDeploymentDependencies.puml
@@ -0,0 +1,25 @@
+'-------------------------------------------------------------------------------
+' Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+'
+' SPDX-License-Identifier: BSD-3-Clause
+'
+'-------------------------------------------------------------------------------
+
+@startuml
+
+package Deployment
+package Application
+package Infrastructure
+package Environment
+package Platform
+package BuildConfig
+package Adapter
+
+Deployment -down.> Application
+Deployment -down.> Infrastructure
+Deployment -down.> Environment
+Deployment -down.> "0..1" Platform
+Deployment -down.> "0..1" BuildConfig
+Infrastructure -down.> "0..*" Adapter
+
+@enduml \ No newline at end of file
diff --git a/docs/developer/uml/SpmcTestStructure.puml b/docs/developer/uml/SpmcTestStructure.puml
new file mode 100644
index 000000000..4b015b112
--- /dev/null
+++ b/docs/developer/uml/SpmcTestStructure.puml
@@ -0,0 +1,34 @@
+'-------------------------------------------------------------------------------
+' Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+'
+' SPDX-License-Identifier: BSD-3-Clause
+'
+'-------------------------------------------------------------------------------
+
+@startuml
+package "Normal World" {
+ package "EL-1" {
+ [arm-ffa-user] as driver
+ [Linux kernel] as kernel
+ }
+ package "EL-0" {
+ [shell]
+ [xtest]
+ }
+}
+package "Secure World" {
+ package "SEL-0" {
+ [Test SP] as sp
+ }
+ package "SEL-1" {
+ [OP-TEE kernel] as optee
+ }
+}
+
+[shell] -> driver: Load driver
+[shell] -> [xtest] : Call xtest -t ffa_spmc
+[xtest] -> driver: Open
+driver -> kernel: Send FF-A message
+kernel -> optee: Forward FF-A message
+optee -> sp: Forward FF-A message
+@enduml
diff --git a/docs/developer/uml/TSRPCCall.puml b/docs/developer/uml/TSRPCCall.puml
new file mode 100644
index 000000000..9359d2728
--- /dev/null
+++ b/docs/developer/uml/TSRPCCall.puml
@@ -0,0 +1,107 @@
+'-------------------------------------------------------------------------------
+' Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+'
+' SPDX-License-Identifier: BSD-3-Clause
+'
+'-------------------------------------------------------------------------------
+
+@startuml TS RPC call sequence
+
+autoactivate on
+
+participant "Service caller" as service_caller
+participant "RPC caller session" as rpc_session
+participant "TS RPC caller" as rpc_caller
+participant "SPMC" as spmc
+participant "TS RPC endpoint" as endpoint
+participant "Service" as service
+
+service_caller -> rpc_session: open(service_uuid)
+
+' Sesssion open
+rpc_session -> rpc_caller: find_and_open_session(service_uuid)
+
+rpc_caller -> spmc: FFA_PARTITION_INFO_GET(ts_rpc_uuid)
+spmc --> rpc_caller: FF-A endpoint_id
+
+rpc_caller -> endpoint: TS_RPC_VERSION_GET
+endpoint --> rpc_caller: TS RPC protocol version
+
+rpc_caller -> endpoint: TS_RPC_SERVICE_INFO_GET(service_uuid)
+endpoint --> rpc_caller: Service interface_id
+
+rpc_caller --> rpc_session: TS RPC status
+
+rpc_session --> service_caller: TS RPC status
+
+' Begin
+service_caller -> rpc_session: begin(request_length, response_max_length)
+
+rpc_session -> rpc_session: allocate_buffer(MAX(request_length, response_max_length))
+rpc_session --> rpc_session: buffer
+
+rpc_session -> rpc_caller: create_shared_memory(endpoint_id, buffer)
+
+rpc_caller -> spmc: FFA_MEM_SHARE(endpoint_id, buffer)
+spmc --> rpc_caller: memory_handle, memory_tag
+
+rpc_caller -> endpoint: TS_RPC_MEM_RETRIEVE(memory_handle, memory_tag)
+
+endpoint -> spmc: FFA_MEM_RETRIEVE(memory_handle, memory_tag)
+spmc --> endpoint: buffer
+
+endpoint --> rpc_caller: TS RPC status
+
+rpc_caller --> rpc_session: TS RPC status, shared_memory
+
+rpc_session --> service_caller: Request buffer
+
+' Serialize
+service_caller -> service_caller: Serialize parameters to request buffer
+service_caller --> service_caller
+
+' Invoke
+service_caller -> rpc_session: invoke(opcode)
+
+rpc_session -> rpc_caller: call(opcode, shared_memory, request_length)
+
+rpc_caller -> endpoint: service_call(interface_id, opcode, memory_handle, request_length)
+
+endpoint -> service: service_call(opcode, request)
+service --> endpoint: service status, response
+
+endpoint --> rpc_caller: TS RPC status, service status, response length
+
+rpc_caller --> rpc_session: TS RPC status, service status, response length
+
+rpc_session --> service_caller: TS RPC status, service status, response
+
+' Deserialize
+service_caller -> service_caller: Deserialize return values from the response buffer
+service_caller --> service_caller
+
+' End
+service_caller -> rpc_session: end()
+
+rpc_session -> rpc_caller: release_shared_memory(shared_memory)
+
+rpc_caller -> endpoint: TS_RPC_MEM_RELINQUISH(memory_handle)
+
+endpoint -> spmc: FFA_MEMORY_RELINQUISH(memory_handle)
+spmc --> endpoint: FFA_SUCCESS
+
+endpoint --> rpc_caller: TS RPC status
+
+rpc_caller -> spmc: FFA_MEM_RECLAIM(memory_handle)
+spmc --> rpc_caller: FFA_SUCCESS
+
+rpc_caller -> rpc_caller: free(buffer)
+rpc_caller --> rpc_caller
+
+rpc_caller --> rpc_session: TS RPC status
+
+rpc_session --> service_caller: TS RPC status
+
+service_caller -> rpc_session: close()
+rpc_session --> service_caller: TS RPC status
+@enduml
diff --git a/docs/developer/writing-documentation.rst b/docs/developer/writing-documentation.rst
index eb10449e3..243dcec2a 100644
--- a/docs/developer/writing-documentation.rst
+++ b/docs/developer/writing-documentation.rst
@@ -40,14 +40,15 @@ documentation into this manual.
CMake
'''''
-.. todo:: Add content about how to document cmake scripts.
-
+The project uses the ""`moderncmakedomain`_" Sphinx extension. This allows adding inline documentation to cmake files.
+For details please refer to the documentation of the plugin.
--------------
.. _`Restructured Text`: https://docutils.sourceforge.io/rst.html
.. _`Sphinx`: https://www.sphinx-doc.org
+.. _`moderncmakedomain`: https://github.com/scikit-build/moderncmakedomain
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/deployment-guides/fvp-deployment-guide.rst b/docs/environments/deployment-guides/fvp-deployment-guide.rst
deleted file mode 100644
index eeb90780f..000000000
--- a/docs/environments/deployment-guides/fvp-deployment-guide.rst
+++ /dev/null
@@ -1,86 +0,0 @@
-Deploying Programs on FVP
-=========================
-This page explains how to load and run user space programs on a Linux image running in FVP simulation.
-The loaded programs may use any trusted services that are available as part of the image firmware.
-
-To prepare and run an image that includes trusted services running in S-EL0 secure partitions under
-OP-TEE. see:
-:ref:`Deploying trusted services in S-EL0 Secure Partitions under OP-TEE`
-
-Shared directory
-----------------
-The OP-TEE image built for the FVP virtual platform supports directory sharing between the running
-OS and the host computer. This provides a convenient way to transfer files between the host and
-the device simulation. When the FVP is run using the *run-only* target in *fvp.mk*, the shared
-directory is set-up automatically.
-
-On the host, the shared directory is located here::
-
- optee/shared
-
-On the simulated device, running under FVP, a mount is created here::
-
- /mnt
-
-Deploying service level tests
------------------------------
-As an example of how to load and run programs, the *ts-service-test* binary executable is used.
-The build file for the *arm-linux* deployment of *ts-service-test* lives under::
-
- trusted-services/deployments/ts-service-test/arm-linux
-
-The executable includes service level test cases that exercise trusted services via their
-standard interfaces. Test cases use *libts* for locating services and establishing RPC
-sessions. *ts-service-test* provides a useful reference for understanding how *libts* may
-be used for accessing trusted services.
-
-The build file for the *arm-linux* deployment of *libts* lives under::
-
- trusted-services/deployments/libts/arm-linux
-
-Trusted service build instructions are here:
-:ref:`Build Instructions`
-
-Having built *ts-service-test* and *libts* for the *arm-linux* environment, the steps
-are required.
-
-Copy files to share directory
-'''''''''''''''''''''''''''''
-Assuming that the *OP-TEE* and *trusted-services* projects are located under a common
-parent directory, the following files need to be copied from the host using::
-
- cp trusted-services/deployments/libts/arm-linux/build/install/lib/libts.so optee/shared/.
- cp trusted-services/deployments/ts-service-test/arm-linux/build/install/bin/ts-service-test optee/shared/.
-
-Installing libts.so
-'''''''''''''''''''
-Having copied *libts.so* to the shared directory, it needs to be copied to one of the standard
-lib directories so that it is located when a dependent program is started. From the terminal
-command prompt for the booted FVP, use::
-
- cd /mnt
- cp libts.so /usr/lib/.
-
-Running the program executable
-''''''''''''''''''''''''''''''
-The *ts-service-test* program may be run directly from the */mnt* directory using::
-
- ./ts-service-test -v
-
-If all is well, you should see something like::
-
- TEST(E2EcryptoOpTests, generateRandomNumbers) - 3 ms
- TEST(E2EcryptoOpTests, asymEncryptDecrypt) - 8 ms
- TEST(E2EcryptoOpTests, signAndVerifyHash) - 29 ms
- TEST(E2EcryptoOpTests, exportAndImportKeyPair) - 17 ms
- TEST(E2EcryptoOpTests, exportPublicKey) - 10 ms
- TEST(E2EcryptoOpTests, generatePersistentKeys) - 34 ms
- TEST(E2EcryptoOpTests, generateVolatileKeys) - 16 ms
-
- OK (7 tests, 7 ran, 56 checks, 0 ignored, 0 filtered out, 117 ms)
-
---------------
-
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
-
-SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/deployment-guides/opteesp-deployment-guide.rst b/docs/environments/deployment-guides/opteesp-deployment-guide.rst
deleted file mode 100644
index e71140fa8..000000000
--- a/docs/environments/deployment-guides/opteesp-deployment-guide.rst
+++ /dev/null
@@ -1,97 +0,0 @@
-Deploying trusted services in S-EL0 Secure Partitions under OP-TEE
-==================================================================
-
-Trusted services built for the *opteesp* environment may be deployed to run within S-EL0 secure
-partitions, managed by OP-TEE. Secure partitions are loaded and run by OP-TEE using the early-TA
-feature where a set of TAs or SPs are loaded during OP-TEE initialization. This feature relies on
-SP images being incorporated into the *OP-TEE OS* image at build time. It is therefore necessary to
-have access to the OP-TEE build environment and tools in order to deploy SP images.
-
-Tool prerequisites and general build instruction for OP-TEE are described here:
-`<https://optee.readthedocs.io/en/latest/building/gits/build.html>`_
-
-Download page for Arm Fixed Virtual Platforms (FVP):
-`<https://developer.arm.com/tools-and-software/simulation-models/fixed-virtual-platforms>`_
-
-Incorporating SP images into the *OP-TEE OS* image
---------------------------------------------------
-
-The set of SP images to include in the built *OP-TEE OS* image are specified to the *OP-TEE OS*
-build by the EARLY_TA_PATHS make variable. The EARLY_TA_PATHS variable should be assigned a string
-containing a space separated list of file paths for each SP image file to include. SP images
-that need to be deployed from the Trusted Services project will be located in the install directory,
-specified when the SP images where built i.e.::
-
- <CMAKE_INSTALL_PREFIX>/bin
-
-The following example illustrates a setting of the EARLY_TA_PATHS variable to deploy the Secure Storage
-SP and Crypto SP::
-
- EARLY_TA_PATHS="ts-install-dir/bin/dc1eef48-b17a-4ccf-ac8b-dfcff7711b14.stripped.elf \
- ts-install-dir/bin/d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0.stripped.elf"
-
-To help with integration with the OP-TEE build system, the installation step for a deployment to the
-*opteesp* environment includes the generation of a simple makefile that extends the EARLY_TA_PATHS
-variable for the particular deployment. For example, the generated makefile for the crypto SP
-contains::
-
- OPTEE_OS_COMMON_EXTRA_FLAGS+=EARLY_TA_PATHS+=${TS_INSTALL_PREFIX}/bin/d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0.stripped.elf
-
-The generated makefile is installed to::
-
- <CMAKE_INSTALL_PREFIX>/lib/make
-
-Reference OP-TEE build with PSA RoT Services
---------------------------------------------
-To provide an example integration of OP-TEE with a set of trusted services, a makefile called *fvp_ffa.mk*
-is included in the OP-TEE build repository that builds OP-TEE OS with a set of SP images that provide PSA
-RoT services. SP images are built using the standard trusted services build flow and are automatically
-injected into the *optee_os* build using the early TA feature described above.
-
-A bootable Linux image is created that is intended to run on the Arm FVP virtual platform. The built image
-includes user space programs that may be used to test and demonstrate the deployed trusted services.
-
-Setting up the OP-TEE build environment
-'''''''''''''''''''''''''''''''''''''''
-To help setup the OP-TEE build environment, a manifest file called *psa-sp-fvp.xml* is included in OP-TEE
-manifests repository. This may be used with the *repo* tool to manage the set of git repositories. Note
-that this manifest relies on SSH access to *github.com* so ensure that you have installed a suitable public
-key into your *github* account.
-
-Having created a new directory for the OP-TEE build environment, the required set of git repositories can
-be cloned and fetched using::
-
- repo init -u https://git.trustedfirmware.org/OP-TEE/manifest.git -b psa-development -m psa-sp-fvp.xml
- repo sync
-
-Building the reference OP-TEE image
-'''''''''''''''''''''''''''''''''''
-To build the bootable image that includes OP-TEE and the set of secure partition images that hold the
-PSA RoT services, use the following (from your OP-TEE root directory)::
-
- cd build
- make -f fvp_ffa.mk all
-
-This will take many tens of minutes to complete.
-
-Running the reference OP-TEE image on FVP
-'''''''''''''''''''''''''''''''''''''''''
-The fvp makefile includes a *run* and *run-only* target which can be used to start the FVP model and
-boot the built image. The example assumes that the FVP model has been installed in the following
-directory relative to the OP-TEE build directory::
-
- ../Foundation_Platformpkg/models/Linux64_GCC-6.4/
-
-To boot the built image on FVP without building, use::
-
- make run-only FVP_PATH=../Foundation_Platformpkg/models/Linux64_GCC-6.4/
-
-For information on running user space programs on FVP, see:
-
-:ref:`Deploying Programs on FVP`
-
---------------
-
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
-
-SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/index.rst b/docs/environments/index.rst
index a2448270a..599e88e64 100644
--- a/docs/environments/index.rst
+++ b/docs/environments/index.rst
@@ -1,16 +1,20 @@
-Processing Environments
-=======================
+Environments
+============
+
+Depending on Arm architecture and SoC capabilities, there may be different options for
+implementing hardware-backed isolation for protecting security sensitive workloads and
+their assets. The Trusted Services project decouples service related components from
+any particular environment, enabling services to be deployed in different environments.
+This section provides information about supported secure processing environments.
.. toctree::
:maxdepth: 1
- :caption: Contents:
+ :caption: Supported Environments:
- ffa/libsp
- deployment-guides/fvp-deployment-guide.rst
- deployment-guides/opteesp-deployment-guide.rst
+ secure-partitions/index
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/secure-partitions/ff-a/index.rst b/docs/environments/secure-partitions/ff-a/index.rst
new file mode 100644
index 000000000..e47443389
--- /dev/null
+++ b/docs/environments/secure-partitions/ff-a/index.rst
@@ -0,0 +1,18 @@
+Firmware Framework for Armv8-A
+==============================
+The |FF-A| specification defines a software architecture that isolates Secure world firmware images from each other. The
+specification defines interfaces that standardize communication between various images. This includes communication
+between images in the Secure world and Normal world.
+
+The Trusted Services project includes service providers that may be deployed within FF-A S-EL0 secure partitions. This
+includes service providers that form the security foundations needed for meeting PSA Certified requirements. Other secure
+partitions are available such as the SMM Gateway to provide Secure world backing for UEFI services.
+
+The component :ref:`libsp` captures helpful abstractions to allow easy FF-A compliant S-EL0 SP development. S-EL0 SPs
+are SPMC agonistic and can be used with an SPMC running in any higher secure exception level (S-EL1 - S-EL3).
+
+--------------
+
+*Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/secure-partitions/index.rst b/docs/environments/secure-partitions/index.rst
new file mode 100644
index 000000000..5680a921d
--- /dev/null
+++ b/docs/environments/secure-partitions/index.rst
@@ -0,0 +1,40 @@
+Secure Partitions
+=================
+
+:term:`Secure Partitions<Secure Partition>` are defined by the :term:`FF-A` standard
+
+Secure partitions are isolated processing environments managed by a Secure Partition Manager (SPM).
+An SPM performs the role of hypervisor for the Arm Secure State and is responsible for managing
+SP initialization, memory management and messaging. The Arm Firmware Framework for A-Profile (FF-A)
+specification (`FF-A Specification`_) defines the set of firmware features that enable the use of
+secure partitions for protecting sensitive workloads.
+
+The Armv8.4 architecture introduces the virtualization extension in the Secure state. For silicon
+based on Armv8.4 (or above) that implement the Secure-EL2 extension, the `Hafnium Project`_
+provides a reference SPMC implementation. For pre-Arm8.4 silicon, the `OP-TEE Project`_ provides
+an alternative reference SPMC implementation.
+
+Within the Trusted Services, the environments realized by the two reference SPM implementations
+are named as follows:
+
+ * *hfsp* - for service deployment under Hafnium
+ * *opteesp* - for service deployment under OP-TEE
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents:
+
+ ff-a/index
+ spm/optee/index
+ spm/hafnium/index
+ libsp
+
+--------------
+
+.. _`FF-A Specification`: https://developer.arm.com/documentation/den0077/latest
+.. _`Hafnium Project`: https://www.trustedfirmware.org/projects/hafnium/
+.. _`OP-TEE Project`: https://www.trustedfirmware.org/projects/op-tee/
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/ffa/libsp.rst b/docs/environments/secure-partitions/libsp.rst
index ff1b55210..ff1b55210 100644
--- a/docs/environments/ffa/libsp.rst
+++ b/docs/environments/secure-partitions/libsp.rst
diff --git a/docs/environments/secure-partitions/spm/hafnium/index.rst b/docs/environments/secure-partitions/spm/hafnium/index.rst
new file mode 100644
index 000000000..e6559c7cf
--- /dev/null
+++ b/docs/environments/secure-partitions/spm/hafnium/index.rst
@@ -0,0 +1,19 @@
+S-EL1 Secure Partitions under Hafnium
+=====================================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents:
+
+*Note: The Arm Total Compute solution is the current reference for running SPs for meeting
+PSA Certified requirements under Hafnium. The 'hfsp_shim' environment is used for deploying
+service providers under Hafnium. Files related to this environment are still in-flux and
+have not yet been up-streamed to TS.* See `Total Compute`_
+
+--------------
+
+.. _`Total Compute`: https://developer.arm.com/tools-and-software/open-source-software/arm-platforms-software/total-compute-solution
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/secure-partitions/spm/optee/index.rst b/docs/environments/secure-partitions/spm/optee/index.rst
new file mode 100644
index 000000000..214988053
--- /dev/null
+++ b/docs/environments/secure-partitions/spm/optee/index.rst
@@ -0,0 +1,15 @@
+S-EL0 Secure Partitions under OP-TEE
+====================================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents:
+
+ userspace-programs-on-fvp
+ opteesp-deployment-guide
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/secure-partitions/spm/optee/opteesp-deployment-guide.rst b/docs/environments/secure-partitions/spm/optee/opteesp-deployment-guide.rst
new file mode 100644
index 000000000..233a189f4
--- /dev/null
+++ b/docs/environments/secure-partitions/spm/optee/opteesp-deployment-guide.rst
@@ -0,0 +1,91 @@
+Deploying trusted services in S-EL0 Secure Partitions under OP-TEE
+==================================================================
+
+Trusted services built for the *opteesp* environment may be deployed to run within S-EL0 secure
+partitions, managed by OP-TEE. The current implementation of the OP-TEE SPMC supports booting SPs
+embedded into the OP-TEE OS binary (similar to early-TAs) or from the FIP.
+
+Tool prerequisites and general build instruction for OP-TEE are described here:
+`<https://optee.readthedocs.io/en/latest/building/gits/build.html>`_
+
+Download page for Arm Fixed Virtual Platforms (FVP):
+`<https://developer.arm.com/tools-and-software/simulation-models/fixed-virtual-platforms>`_
+
+
+Embedding SP images into the *OP-TEE OS* image
+----------------------------------------------
+
+The set of SP images to include in the built *OP-TEE OS* image are specified to the *OP-TEE OS*
+build by the ``SP_PATHS`` make variable. The ``SP_PATHS`` variable should be assigned a string
+containing a space separated list of file paths for each SP image file to include. SP images
+that need to be deployed from the Trusted Services project will be located in the install directory,
+specified when the SP images where built i.e.::
+
+ <CMAKE_INSTALL_PREFIX>/opteesp/bin
+
+The following example illustrates a setting of the ``SP_PATHS`` variable to deploy the Secure Storage
+SP and Crypto SP::
+
+ SP_PATHS="ts-install-dir/opteesp/bin/dc1eef48-b17a-4ccf-ac8b-dfcff7711b14.stripped.elf \
+ ts-install-dir/opteesp/bin/d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0.stripped.elf"
+
+
+Reference OP-TEE build with PSA RoT Services
+--------------------------------------------
+
+To provide an example integration of OP-TEE with a set of trusted services, a makefile called
+*fvp-ps-sp.mk* is included in the OP-TEE build repository that builds OP-TEE OS with a set of SP
+images. SP images are built using the standard trusted services build flow and are automatically
+injected into the *optee_os* build using the TA feature described above.
+
+A bootable Linux image is created that is intended to run on the Arm AEM FVP virtual platform. The
+built image includes user space programs that may be used to test and demonstrate the deployed
+trusted services.
+
+
+Getting build dependencies
+''''''''''''''''''''''''''
+
+To help setup the workspace, a manifest file called *fvp-ts.xml* is included in OP-TEE manifests
+repository. This may be used with the *repo* tool to manage the set of git repositories.
+
+Having created a new directory for the workspace, the required set of git repositories can be cloned
+and fetched using::
+
+ repo init -u https://github.com/OP-TEE/manifest.git -b master -m fvp-ts.xml
+ repo sync
+
+
+Building the reference OP-TEE image
+'''''''''''''''''''''''''''''''''''
+
+To build the bootable image that includes OP-TEE and the set of secure partition images that hold the
+PSA RoT services, use the following (from the root directory of the workspace)::
+
+ make -C build
+
+This will take many tens of minutes to complete.
+
+
+Running the reference OP-TEE image on FVP
+'''''''''''''''''''''''''''''''''''''''''
+
+The fvp makefile includes a *run* and *run-only* target which can be used to start the FVP model and
+boot the built image. The example assumes that the FVP model has been installed in the following
+directory relative to the OP-TEE build directory::
+
+ ../Base_RevC_AEMvA_pkg/models/Linux64_GCC-9.3
+
+To boot the built image on FVP without building, use::
+
+ FVP_PATH=../Base_RevC_AEMvA_pkg/models/Linux64_GCC-9.3 make run-only
+
+For information on running user space programs on FVP, see:
+
+:ref:`Running User-space Programs on FVP`
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/environments/secure-partitions/spm/optee/userspace-programs-on-fvp.rst b/docs/environments/secure-partitions/spm/optee/userspace-programs-on-fvp.rst
new file mode 100644
index 000000000..f81e1dff3
--- /dev/null
+++ b/docs/environments/secure-partitions/spm/optee/userspace-programs-on-fvp.rst
@@ -0,0 +1,150 @@
+Running user-space programs on FVP
+==================================
+
+This page explains how to load and run user space programs on a Linux image running in FVP simulation.
+The loaded programs may use any trusted services that are available as part of the image firmware.
+
+To prepare and run an image that includes trusted services running in S-EL0 secure partitions under
+OP-TEE see: :ref:`Deploying trusted services in S-EL0 Secure Partitions under OP-TEE`
+
+The example assumes that the FVP model has been installed in the following
+directory relative to the OP-TEE build directory::
+
+ ../Base_RevC_AEMvA_pkg/models/Linux64_GCC-9.3
+
+
+Shared directory
+----------------
+
+The AEM FVP supports directory sharing between the target and the host OS. This provides a
+convenient way to transfer files between the host and the device simulation. When the FVP is run
+using the *run-only* target from the *op-tee/build* repository, the shared directory is set-up
+automatically. The whole "workspace" is shared to the FVP and mounted under ``/mnt/host``.
+
+
+Running service level tests
+---------------------------
+
+Most test and demo applications are integrated into the OP-TEE build flow, and can be build using
+the makefiles in the ``op-tee/build`` repository.
+
+To build all such binaries build the ``ffa-test-all`` target. For available targets please refer to
+`fvp-psa-sp.mk`. As an example to build the ``ts-service-test`` application execute the following
+commands from the root of the workspace::
+
+ make -C build ffa-ts-service-test
+
+The executable includes service level test cases that exercise trusted services via their
+standard interfaces. Test cases use *libts* for locating services and establishing RPC
+sessions. *ts-service-test* provides a useful reference for understanding how *libts* may
+be used for accessing trusted services.
+
+Build output will be copied to ``out/ts-install``.
+
+To build the applications without using the ``op-tee/build`` files refer to the instructions here:
+:ref:`Build Instructions`
+
+Run *ts-service-test*
+'''''''''''''''''''''
+
+To start the FVP, from the root directory of the workspace, enter::
+
+ FVP_PATH=../Base_RevC_AEMvA_pkg/models/Linux64_GCC-9.3 make -C build run-only
+
+Once it boots to the login prompt, log in as root and from the FVP terminal, enter::
+
+ # Enter the mount target for the shared directory
+ cd /mnt/host
+
+ # Install the shared library and executables
+ cp -vat /usr out/ts-install/arm-linux/lib out/ts-install/arm-linux/bin
+
+ # Load the kernel modules
+ out/linux-arm-ffa-tee/load_module.sh
+ out/linux-arm-ffa-user/load_module.sh
+
+ # Run the test application
+ ts-service-test -v
+
+Use the same flow for other user-space programs. Check the output of the ``cp`` command executed to see
+executables copied under ``/usr/bin``.
+
+If all is well, you should see something like::
+
+ TEST(PsServiceTests, createAndSetExtended) - 0 ms
+ TEST(PsServiceTests, createAndSet) - 0 ms
+ TEST(PsServiceTests, storeNewItem) - 0 ms
+ TEST(ItsServiceTests, storeNewItem) - 0 ms
+ TEST(AttestationProvisioningTests, provisionedIak) - 1 ms
+ TEST(AttestationProvisioningTests, selfGeneratedIak) - 1 ms
+ TEST(AttestationServiceTests, repeatedOperation) - 75 ms
+ TEST(AttestationServiceTests, invalidChallengeLen) - 0 ms
+ TEST(AttestationServiceTests, checkTokenSize) - 2 ms
+ TEST(CryptoKeyDerivationServicePackedcTests, deriveAbort) - 0 ms
+ TEST(CryptoKeyDerivationServicePackedcTests, hkdfDeriveBytes) - 0 ms
+ TEST(CryptoKeyDerivationServicePackedcTests, hkdfDeriveKey) - 0 ms
+ TEST(CryptoMacServicePackedcTests, macAbort) - 0 ms
+ TEST(CryptoMacServicePackedcTests, signAndVerify) - 1 ms
+ TEST(CryptoCipherServicePackedcTests, cipherAbort) - 0 ms
+ TEST(CryptoCipherServicePackedcTests, encryptDecryptRoundtrip) - 0 ms
+ TEST(CryptoHashServicePackedcTests, hashAbort) - 0 ms
+ TEST(CryptoHashServicePackedcTests, hashAndVerify) - 0 ms
+ TEST(CryptoHashServicePackedcTests, calculateHash) - 0 ms
+ TEST(CryptoServicePackedcTests, generateRandomNumbers) - 0 ms
+ TEST(CryptoServicePackedcTests, asymEncryptDecryptWithSalt) - 14 ms
+ TEST(CryptoServicePackedcTests, asymEncryptDecrypt) - 1 ms
+ TEST(CryptoServicePackedcTests, signAndVerifyEat) - 4 ms
+ TEST(CryptoServicePackedcTests, signAndVerifyMessage) - 4 ms
+ TEST(CryptoServicePackedcTests, signAndVerifyHash) - 4 ms
+ TEST(CryptoServicePackedcTests, exportAndImportKeyPair) - 1 ms
+ TEST(CryptoServicePackedcTests, exportPublicKey) - 1 ms
+ TEST(CryptoServicePackedcTests, purgeKey) - 0 ms
+ TEST(CryptoServicePackedcTests, copyKey) - 1 ms
+ TEST(CryptoServicePackedcTests, generatePersistentKeys) - 1 ms
+ TEST(CryptoServicePackedcTests, generateVolatileKeys) - 0 ms
+ TEST(CryptoServiceProtobufTests, generateRandomNumbers) - 1 ms
+ TEST(CryptoServiceProtobufTests, asymEncryptDecryptWithSalt) - 15 ms
+ TEST(CryptoServiceProtobufTests, asymEncryptDecrypt) - 1 ms
+ TEST(CryptoServiceProtobufTests, signAndVerifyMessage) - 4 ms
+ TEST(CryptoServiceProtobufTests, signAndVerifyHash) - 4 ms
+ TEST(CryptoServiceProtobufTests, exportAndImportKeyPair) - 1 ms
+ TEST(CryptoServiceProtobufTests, exportPublicKey) - 0 ms
+ TEST(CryptoServiceProtobufTests, generatePersistentKeys) - 1 ms
+ TEST(CryptoServiceProtobufTests, generateVolatileKeys) - 1 ms
+ TEST(CryptoServiceLimitTests, volatileRsaKeyPairLimit) - 99 ms
+ TEST(CryptoServiceLimitTests, volatileEccKeyPairLimit) - 22 ms
+ TEST(DiscoveryServiceTests, checkServiceInfo) - 0 ms
+ TEST(SmmVariableAttackTests, getCheckPropertyWithMaxSizeName) - 0 ms
+ TEST(SmmVariableAttackTests, getCheckPropertyWithOversizeName) - 0 ms
+ TEST(SmmVariableAttackTests, setCheckPropertyWithMaxSizeName) - 0 ms
+ TEST(SmmVariableAttackTests, setCheckPropertyWithOversizeName) - 0 ms
+ TEST(SmmVariableAttackTests, enumerateWithSizeMaxNameSize) - 0 ms
+ TEST(SmmVariableAttackTests, enumerateWithOversizeName) - 0 ms
+ TEST(SmmVariableAttackTests, setAndGetWithSizeMaxNameSize) - 0 ms
+ TEST(SmmVariableAttackTests, setAndGetWithOversizeName) - 0 ms
+ TEST(SmmVariableAttackTests, setWithSizeMaxNameSize) - 0 ms
+ TEST(SmmVariableAttackTests, setWithOversizeName) - 0 ms
+ TEST(SmmVariableAttackTests, setWithSizeMaxDataSize) - 0 ms
+ TEST(SmmVariableAttackTests, setWithOversizeData) - 0 ms
+ TEST(SmmVariableServiceTests, checkMaxVariablePayload) - 0 ms
+ TEST(SmmVariableServiceTests, setSizeConstraint) - 0 ms
+ TEST(SmmVariableServiceTests, enumerateStoreContents) - 0 ms
+ TEST(SmmVariableServiceTests, getVarSizeNv) - 0 ms
+ TEST(SmmVariableServiceTests, getVarSize) - 0 ms
+ TEST(SmmVariableServiceTests, setAndGetNv) - 1 ms
+ TEST(SmmVariableServiceTests, setAndGet) - 0 ms
+ TEST(TestRunnerServiceTests, runSpecificTest) - 0 ms
+ TEST(TestRunnerServiceTests, runConfigTests) - 0 ms
+ TEST(TestRunnerServiceTests, listPlatformTests) - 0 ms
+ TEST(TestRunnerServiceTests, runAllTests) - 0 ms
+ TEST(TestRunnerServiceTests, listAllTests) - 0 ms
+
+ OK (67 tests, 67 ran, 977 checks, 0 ignored, 0 filtered out, 261 ms)
+
+--------------
+
+.. _fvp-psa-sp.mk: https://github.com/OP-TEE/build/blob/master/fvp-psa-sp.mk
+
+*Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/global_substitutions.txt b/docs/global_substitutions.txt
index 7ec8d7446..67f261fc9 100644
--- a/docs/global_substitutions.txt
+++ b/docs/global_substitutions.txt
@@ -11,14 +11,17 @@
.. |SEMVER| replace:: `Semantic Versioning`_
.. |PSA| replace:: :term:`PSA`
.. |FF-A| replace:: :term:`FF-A`
+.. |TRUSTZONE| replace:: :term:`TrustZone`
+.. |NWd| replace:: :term:`Normal World`
+.. |SWd| replace:: :term:`Secure World`
-.. _`TS Mailing List`: https://lists.trustedfirmware.org/mailman/listinfo/trusted-services
+.. _`TS Mailing List`: https://lists.trustedfirmware.org/mailman3/lists/trusted-services.lists.trustedfirmware.org/
.. _`TS repository`: https://review.trustedfirmware.org/admin/repos/TS/trusted-services
.. _`Semantic Versioning`: https://semver.org/spec/v2.0.0.html
..
--------------
- *Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+ *Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/index.rst b/docs/index.rst
index cb44e2c3c..1135ba710 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,51 +1,66 @@
Trusted Services Documentation
==============================
The Trusted Services project provides a framework for developing and deploying device
-root-of-trust services across a range of secure processing environments such as those
-provided by OP-TEE and Hafnium.
+root-of-trust services for A-profile devices. Alternative secure processing environments
+are supported to accommodate the diverse range of isolation technologies available to
+system integrators.
.. raw:: html
<ul class="grid">
<li class="grid-item">
<a href="overview/index.html">
- <img alt="" src="_static/images/tfm.png"/>
- <h2>About trusted services</h2>
+ <img alt="" src="_static/images/tfm-introduction.png"/>
+ <h2>Introduction</h2>
</a>
<p></p>
</li>
<li class="grid-item">
<a href="project/index.html">
- <img alt="" src="_static/images/tfm.png"/>
- <h2>About the project</h2>
+ <img alt="" src="_static/images/tfm-contribution.png"/>
+ <h2>About the Project</h2>
</a>
<p></p>
</li>
<li class="grid-item">
- <a href="developer/index.html">
- <img alt="" src="_static/images/tfm.png"/>
- <h2>Developer Docs</h2>
+ <a href="quickstart/index.html">
+ <img alt="" src="_static/images/tfm-documentation.png"/>
+ <h2>Quick Start Guides</h2>
+ </a>
+ <p></p>
+ </li>
+ <li class="grid-item">
+ <a href="services/index.html">
+ <img alt="" src="_static/images/tfm-integration.png"/>
+ <h2>Services</h2>
</a>
<p></p>
</li>
<li class="grid-item">
<a href="environments/index.html">
<img alt="" src="_static/images/tfm.png"/>
- <h2>Processing Environments</h2>
+ <h2>Secure Processing Environments</h2>
</a>
<p></p>
</li>
<li class="grid-item">
- <a href="security/index.html">
- <img alt="" src="_static/images/tfm.png"/>
- <h2>Security Model</h2>
+ <a href="deployments/index.html">
+ <img alt="" src="_static/images/tfm-release.png"/>
+ <h2>Deployments</h2>
+ </a>
+ <p></p>
+ </li>
+ <li class="grid-item">
+ <a href="developer/index.html">
+ <img alt="" src="_static/images/tfm-reference.png"/>
+ <h2>Developer Documents</h2>
</a>
<p></p>
</li>
<li class="grid-item">
- <a href="standards/index.html">
+ <a href="certification/index.html">
<img alt="" src="_static/images/tfm.png"/>
- <h2>Standards Compliance</h2>
+ <h2>Platform Certification</h2>
</a>
<p></p>
</li>
@@ -58,13 +73,17 @@ provided by OP-TEE and Hafnium.
overview/index
project/index
+ quickstart/index
developer/index
+ services/index
environments/index
security/index
- standards/index
+ deployments/index
+ certification/index
+ target-platforms/index
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/overview/introduction.rst b/docs/overview/example-usage.rst
index 674e0b50d..68422ba6f 100644
--- a/docs/overview/introduction.rst
+++ b/docs/overview/example-usage.rst
@@ -1,35 +1,11 @@
-What are trusted services?
-==========================
-
-The term 'trusted service' is used as a general name for a class of application that runs in an isolated
-processing environment. Other applications rely on trusted services to perform security related operations in
-a way that avoids exposing secret data beyond the isolation boundary of the environment. The word 'trusted'
-does not imply anything inherently trustworthy about a service application but rather that other applications
-put trust in the service. Meeting those trust obligations relies on a range of hardware and firmware
-implemented security measures.
-
-The Arm architecture, in combination with standard firmware, provides a range of isolated processing environments
-that offer hardware-backed protection against various classes of attack. Because of their strong security
-properties, these environments are suitable for running applications that have access to valuable assets
-such as keys or sensitive user data. The goal of the Trusted Services project is to provide a framework in
-which security related services may be developed, tested and easily deployed to run in any of the supported
-environments. A core set of trusted services are implemented to provide basic device security functions such
-as cryptography and secure storage.
-
-Example isolated processing environments are:
-
- - **Secure partitions** - secure world VMs managed by a secure partition manager
- - **Trusted applications** - application environments managed by a TEE
- - **Integrated microcontroller** - a secondary MCU used as a secure enclave
-
-Typical problems solved by trusted services
--------------------------------------------
+Solving Common Security Problems
+================================
The following are examples of how trusted services can solve common device security problems.
Protecting IoT device identity
-''''''''''''''''''''''''''''''
+------------------------------
During the provisioning process, an IoT device is assigned a secure identity that consists of a public/private
key pair and a CA signed certificate that includes the public key. The device is also provisioned with the
@@ -42,7 +18,7 @@ that performs the operations without exposing the private key.
Protecting Software Updates
-'''''''''''''''''''''''''''
+---------------------------
To ensure that software updates applied to a device originate from a legitimate source, update packages are
signed. A signed package will include a signature block that includes a hash of the package contents within
@@ -53,7 +29,7 @@ source is prevented.
Secure Logging
-''''''''''''''
+--------------
A managed IoT device will often be configured by an installation engineer who has physical access to the
device. To allow a cloud operator to audit configuration changes, it is necessary to keep a log of
@@ -64,6 +40,6 @@ be verified. To protect the signing key, the Crypto service is used for signing
--------------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/overview/image/TsReferencePlatform.svg b/docs/overview/image/TsReferencePlatform.svg
new file mode 100644
index 000000000..1bc7a151b
--- /dev/null
+++ b/docs/overview/image/TsReferencePlatform.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1071px" height="631px" viewBox="-0.5 -0.5 1071 631" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2022-04-29T15:26:49.665Z&quot; agent=&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36&quot; etag=&quot;qAat_TDOYu75N8qs_XeF&quot; version=&quot;15.9.1&quot; type=&quot;atlas&quot;&gt;&lt;mxAtlasLibraries/&gt;&lt;diagram id=&quot;3S9PIcjPeEhHK4FUF1jD&quot; name=&quot;Page-1&quot;&gt;7Vxbd6JIEP41njP7wByaBsRH4yU7u8mMWbObzdMeAq0yQZtp2qj59dsoIHS3lzGgDMk8ZKC4f99HdVV1YQN2pstrYgeTW+wiv6Gp7rIBuw1NAy1NZf9FltXGYra0jWFMPDfeaWsYeq8oNsbHjeeei8LcjhRjn3pB3ujg2Qw5NGezCcGL/G4j7OevGtjj+Irq1jB0bB8Juz14Lp1srJaR2ft35I0nyZWBGm+Z2snOsSGc2C5eZEyw14AdgjHdLE2XHeRH4CW4bI7r79ia3hhBM3rMAdPXL8H8v+uH3uvjP8r0zn3ovr4o8VlebH8eP/C3gXLf6zHbt2F833SVgEHwfOai6HxqA14tJh5Fw8B2oq0LRj+zTejUZ2uALY483+9gH5P1sVBVDRWNmD2kBD+j3BbQvepER+AZzdhH63/MLj5pctuIULTMmOInv0Z4iihZsV3irYoesxDLECYELrakwlZsm2QITWx2rKNxeuot1GwhRvsnkNcE5IeDW2boYILqBLzGAW+KwANNAnyzLOChAHy/r7SZpX31pVDgbdXQNFcGvNkFfVUtF/jmZyMHvA5F4E1DxF0rC3ddFDxy5pHY1Vs88ygDQTN9dhdXT9HSOFr6dM+o+a1Or4PBOSKjKdJiyRyRWRYvxg5H1PXCwKbOBJE64a/x8KfvySGHpBslEWAKBAiAo5nbjoIZtub4dhh6zhpAm1DRnIGe4URW/0Y0sYeMVx+z27rLmMPN2ipZW3o0cxhbe8xs2R4UrSTH7CQnxHPioMMCZE8zRvSw40ZuErHtoDpDpCHhMbER5NvUe8nHeTJy4ysMsMeeLFUSsDgl6dwLunnu+KhsXMadSIP5E+l8yLEBRjjRWmvpY58uP+uw/N7yvrs2skaO8L7P8AyVE9oBiUeVhnbAKMultgRIO2QVUCwOcMNBjZ2rpopMNM8ZYydJpCTmEIhg8UeUCtaboWbVCBLzzzaliI1s1MOzmpMBTKNibEhy0tsoFLy2KVrYq5rzkYbYleHjnaSqCuCT1RTTSyWrQMxWawl9U6sc8mI+WkvkgVk90YuZaC2h18zqqb4pQC8AfrEiANBBpgygqJ9V1dxbC4hWBoh4DBtEGm+tDyTTPofqA6DaBQJd5cRzaoEA8nlryQUCcESF4GLahE3t6BLVhWSpf8iyFFmKVZbCZJnKy2SOueLyMj7kVYa8kqG+kl7PMlq/xIhsfmizFG2KhZp92oxr7a4dTtbxOsjLcacOKkKbwtVlDHgibfyJ+BaDslkTyzlJRS1KdnL0mT/mONmghOuuqCgPA1aw3G5Mq3DJPPoDJr6bnJPd4+a0m50EgbBkieaFIJ2hyWZuscn2vfEscm5MMJE3uYpSL8+x/Xa8Yeq5bnQZaVaYzxt3iu/kojaQlO2kE7pFJHOPxt3j0g17hjruqtevFLe+/yHpdIh6qdQ/EZlF3XEF5tGm3jStpiyPhkCHhl5y3Q7u8oMZ6NNOvqJLplLoxZiwlhUMRTOE/h5dxL6sEoYUesnswd+9PkNdHSLy4jkorJP0+T4eXZN4HeucXufdzBboFl++u7z2xaJ1oYiX30TBu3JZF4XUlRfSRSEHVSxHd3wPrSOldhDUyZtAkEdfNvUocyaljaOSevRguPYlg2J9ieMgYySd8oUmbEG3KIBVruAvaUOWze2W5jEk5YW6ils7oi3orOJOn0GCve89/Yr61kDV9P1zJYrzls80vnoGkqpvwdWzfelhtnq2d/yrSBkGcK+xcWr1DHAJu15e9UwuTVkdpirSbIKsNkuacHiTLBMZfMiyYFmKZaNCR6Lycwg+J5aVg6Q5cRHftsgxFVOIuCZRsxhLzImh7MMiCfZ8Mb047KvXNrAT6cNOr1pjsaLrWt5Z8YHc0XMi6ecm8Zks/mUs2+3JpvGLmBX5isnUji7/PmdFFMgRe/l5kcTVZKju3ag1psBU8xSwEVGgQD8rA2Lm27sB74gBaF2aATHK693Ad8SAIWm1LYuBJrn/Yt3ZD3f9rndj2sZAs39IfvLi0mFJpptxHSheot3s2OyvVa04KJ19SOIg69Q4CHA61fnAeEccxBQRfRmV7hZEO4R7bpk9fP6FMAxO05tTnhplSUVfvWrcTqkerotVq89b0TkNGnxfUfU0KNxyvF6qBsWR757MQ8pGmz0tArUZCCH/7a0kFkz5P8tAKM5ZJ7/9VFsOONlDSSxyXg7E+tT9umfjvTAgiwbPy8Cuie6/MKYKHilrH7XPQ20xAoerhrkeXAldvv2E/AEOvfX37xLabrgdKA6OYfkJU4qnRVUW8gEMkHCoWZL2G1BErfHr88C5MZ+/j8yr0erH6yQYB01JTB+3Pn3qe2S6YE/LlvvEnqIFJs+N6HcACfvbVgKCGQtI/Imp2rxxfExhyhp7ZAnYCWSx1e3vGW7Chu2vQsLe/w==&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="560" y="280" width="390" height="90" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 388px; height: 1px; padding-top: 325px; margin-left: 561px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">OP-TEE OS</div></div></div></foreignObject><text x="755" y="329" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">OP-TEE OS</text></switch></g><rect x="580" y="290" width="120" height="70" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 325px; margin-left: 581px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">SPM Core</div></div></div></foreignObject><text x="640" y="329" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">SPM Core</text></switch></g><rect x="607.5" y="360" width="65" height="20" fill="#a0522d" stroke="#6d1f00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 63px; height: 1px; padding-top: 370px; margin-left: 609px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A ABI</div></div></div></foreignObject><text x="640" y="374" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A ABI</text></switch></g><rect x="60" y="500" width="890" height="60" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 888px; height: 1px; padding-top: 530px; margin-left: 61px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Secure Monitor<br />(TF-A)</div></div></div></foreignObject><text x="505" y="534" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">Secure Monitor...</text></switch></g><rect x="580" y="507.5" width="120" height="45" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 530px; margin-left: 581px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">SPM Dispatcher</div></div></div></foreignObject><text x="640" y="534" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">SPM Dispatcher</text></switch></g><path d="M 640 501.13 L 640 386.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 640 506.38 L 636.5 499.38 L 640 501.13 L 643.5 499.38 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 640 381.12 L 643.5 388.12 L 640 386.37 L 636.5 388.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="560" y="100" width="390" height="150" fill="#dae8fc" stroke="none" pointer-events="all"/><rect x="580" y="130" width="70" height="90" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 175px; margin-left: 581px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Crypto<br />SP</div></div></div></foreignObject><text x="615" y="179" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">Crypto...</text></switch></g><rect x="670" y="130" width="70" height="90" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 175px; margin-left: 671px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Secure<br />Storage<br />SP</div></div></div></foreignObject><text x="705" y="179" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">Secure...</text></switch></g><rect x="765" y="130" width="70" height="90" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 175px; margin-left: 766px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Attestation<br />SP</div></div></div></foreignObject><text x="800" y="179" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">Attestation...</text></switch></g><rect x="860" y="130" width="70" height="90" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 175px; margin-left: 861px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">SMM Gateway<br />SP</div></div></div></foreignObject><text x="895" y="179" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">SMM Gateway...</text></switch></g><rect x="582.5" y="220" width="65" height="20" fill="#a0522d" stroke="#6d1f00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 63px; height: 1px; padding-top: 230px; margin-left: 584px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A ABI</div></div></div></foreignObject><text x="615" y="234" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A ABI</text></switch></g><rect x="672.5" y="220" width="65" height="20" fill="#a0522d" stroke="#6d1f00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 63px; height: 1px; padding-top: 230px; margin-left: 674px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A ABI</div></div></div></foreignObject><text x="705" y="234" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A ABI</text></switch></g><rect x="767.5" y="220" width="65" height="20" fill="#a0522d" stroke="#6d1f00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 63px; height: 1px; padding-top: 230px; margin-left: 769px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A ABI</div></div></div></foreignObject><text x="800" y="234" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A ABI</text></switch></g><rect x="862.5" y="220" width="65" height="20" fill="#a0522d" stroke="#6d1f00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 63px; height: 1px; padding-top: 230px; margin-left: 864px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A ABI</div></div></div></foreignObject><text x="895" y="234" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A ABI</text></switch></g><path d="M 614.99 273.09 L 615 246.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 614.99 278.34 L 611.49 271.34 L 614.99 273.09 L 618.49 271.34 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 615 241.12 L 618.5 248.12 L 615 246.37 L 611.5 248.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 705.07 273.63 L 705.01 246.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 705.08 278.88 L 701.56 271.89 L 705.07 273.63 L 708.56 271.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 705 241.12 L 708.52 248.11 L 705.01 246.37 L 701.52 248.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 800.55 273.63 L 800.21 246.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 800.62 278.88 L 797.03 271.93 L 800.55 273.63 L 804.03 271.84 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 800.14 241.12 L 803.73 248.07 L 800.21 246.37 L 796.73 248.16 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 895.01 273.09 L 895 246.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 895.01 278.34 L 891.51 271.34 L 895.01 273.09 L 898.51 271.34 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 895 241.12 L 898.5 248.12 L 895 246.37 L 891.5 248.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 540 460 L 540 0" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><rect x="670" y="30" width="120" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 40px; margin-left: 671px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><font style="font-size: 18px">Secure World</font></div></div></div></foreignObject><text x="730" y="44" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Secure World</text></switch></g><rect x="270" y="280" width="210" height="90" fill="#647687" stroke="#314354" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 325px; margin-left: 271px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">OS Kernel</div></div></div></foreignObject><text x="375" y="329" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">OS Kernel</text></switch></g><rect x="342.5" y="370" width="65" height="20" fill="#a0522d" stroke="#6d1f00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 63px; height: 1px; padding-top: 380px; margin-left: 344px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A ABI</div></div></div></foreignObject><text x="375" y="384" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A ABI</text></switch></g><rect x="60" y="350" width="180" height="20" fill="#647687" stroke="#314354" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 360px; margin-left: 61px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">UEFI Services</div></div></div></foreignObject><text x="150" y="364" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">UEFI Services</text></switch></g><rect x="117.5" y="370" width="65" height="20" fill="#a0522d" stroke="#6d1f00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 63px; height: 1px; padding-top: 380px; margin-left: 119px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A ABI</div></div></div></foreignObject><text x="150" y="384" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A ABI</text></switch></g><rect x="270" y="100" width="210" height="150" fill="#dae8fc" stroke="none" pointer-events="all"/><rect x="290" y="130" width="80" height="90" fill="#647687" stroke="#314354" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 175px; margin-left: 291px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Client App</div></div></div></foreignObject><text x="330" y="179" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">Client App</text></switch></g><rect x="295" y="190" width="70" height="20" fill="#cce5ff" stroke="#36393d" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 200px; margin-left: 296px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">PSA API</div></div></div></foreignObject><text x="330" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PSA API</text></switch></g><rect x="380" y="130" width="80" height="90" fill="#647687" stroke="#314354" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 175px; margin-left: 381px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Client App</div></div></div></foreignObject><text x="420" y="179" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">Client App</text></switch></g><rect x="385" y="190" width="70" height="20" fill="#cce5ff" stroke="#36393d" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 200px; margin-left: 386px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Client lib</div></div></div></foreignObject><text x="420" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Client lib</text></switch></g><path d="M 330.8 272.64 L 330.1 226.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 330.88 277.89 L 327.28 270.95 L 330.8 272.64 L 334.28 270.84 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 330.02 221.12 L 333.62 228.06 L 330.1 226.37 L 326.62 228.17 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 420.88 273.63 L 420.11 226.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 420.97 278.88 L 417.36 271.94 L 420.88 273.63 L 424.36 271.83 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 420.02 221.12 L 423.63 228.06 L 420.11 226.37 L 416.63 228.17 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="60" y="280" width="180" height="60" fill="#dae8fc" stroke="none" pointer-events="all"/><rect x="117.5" y="300" width="80" height="30" fill="#647687" stroke="#314354" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 315px; margin-left: 119px;"><div data-drawio-colors="color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">UEFI App</div></div></div></foreignObject><text x="158" y="319" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">UEFI App</text></switch></g><path d="M 157.84 343.63 L 157.66 336.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 157.97 348.88 L 154.3 341.97 L 157.84 343.63 L 161.3 341.8 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 157.53 331.12 L 161.2 338.03 L 157.66 336.37 L 154.2 338.2 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="210" y="30" width="120" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 40px; margin-left: 211px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><font style="font-size: 18px">Normal World</font></div></div></div></foreignObject><text x="270" y="44" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Normal World</text></switch></g><rect x="0" y="165" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 175px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">EL0</div></div></div></foreignObject><text x="20" y="179" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">EL0</text></switch></g><rect x="0" y="315" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 325px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">EL1</div></div></div></foreignObject><text x="20" y="329" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">EL1</text></switch></g><rect x="0" y="520" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 530px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">EL3</div></div></div></foreignObject><text x="20" y="534" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">EL3</text></switch></g><path d="M 375.03 493.63 L 375.02 489.32 Q 375 485 375 475 L 375 396.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 375.06 498.88 L 371.53 491.9 L 375.03 493.63 L 378.53 491.87 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 375 391.12 L 378.5 398.12 L 375 396.37 L 371.5 398.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 150 493.63 L 150 486.82 Q 150 480 150 470 L 150 396.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 150 498.88 L 146.5 491.88 L 150 493.63 L 153.5 491.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 150 391.12 L 153.5 398.12 L 150 396.37 L 146.5 398.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="970" y="165" width="100" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 175px; margin-left: 971px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Trusted Services</div></div></div></foreignObject><text x="1020" y="179" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Trusted Services</text></switch></g><rect x="950" y="320" width="100" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 330px; margin-left: 951px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">OP-TEE</div></div></div></foreignObject><text x="1000" y="334" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">OP-TEE</text></switch></g><rect x="950" y="520" width="100" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 530px; margin-left: 951px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">TF-A</div></div></div></foreignObject><text x="1000" y="534" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">TF-A</text></switch></g><rect x="565" y="120" width="285" height="130" rx="19.5" ry="19.5" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 283px; height: 1px; padding-top: 117px; margin-left: 566px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">PSA Root-of-Trust Services</div></div></div></foreignObject><text x="708" y="117" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PSA Root-of-Trust Services</text></switch></g><rect x="700" y="600" width="240" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 238px; height: 1px; padding-top: 615px; margin-left: 701px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A (Firmware Framework for A-profile)</div></div></div></foreignObject><text x="820" y="619" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A (Firmware Framework for A-profile)</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/overview/index.rst b/docs/overview/index.rst
index 4706034ea..3e657ab05 100644
--- a/docs/overview/index.rst
+++ b/docs/overview/index.rst
@@ -1,15 +1,50 @@
-About trusted services
-======================
+Introduction
+============
+
+The term 'trusted service' is used as a general name for a class of application that runs in an isolated
+processing environment. Other applications rely on trusted services to perform security related operations in
+a way that avoids exposing secret data beyond the isolation boundary of the environment. The word 'trusted'
+does not imply anything inherently trustworthy about a service application but rather that other applications
+put trust in the service. Meeting those trust obligations relies on a range of hardware and firmware
+implemented security measures.
+
+The Arm Application-profile (A-profile) architecture, in combination with standard firmware, provides a range
+of isolated processing environments that offer hardware-backed protection against various classes of attack.
+Because of their strong security properties, these environments are suitable for running applications that have
+access to valuable assets such as keys or sensitive user data. The goal of the Trusted Services project is
+to provide a framework in which security related services may be developed, tested and easily deployed to
+run in any of the supported environments. A core set of trusted services are implemented to provide basic
+device security functions such as cryptography and secure storage.
+
+Example isolated processing environments are:
+
+ - **Secure partitions** - secure world isolated environments managed by a secure partition manager
+ - **Trusted applications** - application environments managed by a TEE
+ - **VM backed container** - container runtime that uses a hypervisor to provide hardware backed container isolation
+
+The default reference system, used for test and development, uses the Secure Partition Manager configuration
+of OP-TEE to manage a set of secure partitions running at S-EL0. The secure partitions host service providers
+that implement PSA root-of-trust services. Services may be accessed using client-side C bindings that expose PSA
+Functional APIs. UEFI SMM services are provided by the SMM Gateway.
+
+.. image:: image/TsReferencePlatform.svg
+.. The image was exported from an original on Arm Confluence.
+
+For more background on the type of problems solved by trusted services and how the project aims to
+make solutions more accessible, see:
.. toctree::
:maxdepth: 1
- :caption: Contents:
- introduction
+ example-usage
goals
+The Trusted Services project includes components that may be integrated into platform firmware
+to enable A-profile platforms to meet PSA Certified security requirements. For more information, see:
+:ref:`Platform Certification`.
+
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/project/change-log.rst b/docs/project/change-log.rst
index fbabfa42a..a4ca47ae8 100644
--- a/docs/project/change-log.rst
+++ b/docs/project/change-log.rst
@@ -1,30 +1,163 @@
Change Log & Release Notes
==========================
-This document contains a summary of the new features, changes, fixes and known
-issues in each release of Trusted Services.
+This document contains a summary of the new features, changes, fixes and known issues in each release of Trusted
+Services.
-Version 0.1.0
+Version 1.0.0
-------------
-New Features
-^^^^^^^^^^^^
-First release.
+The first stabilised release of the project from previously prototype releases ready for product use.
-Changes
-^^^^^^^
-None.
+Feature Highlights
+^^^^^^^^^^^^^^^^^^
-Resolved Issues
+- Introduce the :doc:`Block Storage Service </services/block-storage-service-description>`. The Block Storage service
+ can be used to share a block-oriented storage device such as a QSPI flash between a set of independent secure world
+ clients.
+
+- Introduce the :doc:`Firmware Update Service </services/fwu/index>`. The FWU service implements the Update Agent
+ defined in the `Arm FWU-A specification`_ and allows replacing FW components with newer versions.
+
+- Refactor FF-A UUID policy. Reinterpret the FF-A UUID to identify the protocol supported by TS SP instead of the
+ service. This removes the maintenance burden of keeping an up to date UUID list in the service locator. All SPs start
+ using the same protocol UUID, and implement a new discovery service (see the next point).
+
+- Overhaul the RPC protocol. The main driver is to remove the single shared memory region limitation, which does not
+ allow separating shared regions of clients running over Linux in the user-space. The second driver is to add
+ versioning support to the RPC layer.
+
+ - Allow multiple shared memory regions between endpoints.
+ - Implement the discovery service in the RPC layer.
+ - Allow assigning a UUID to interfaces. This mechanism replaces the protocol identifier used earlier. Each protocol
+ of a service is represented as a dedicated interface.
+ - Add versioning support to the RPC layer.
+
+- Refactor the discovery service. The is removing the runtime overhead of memory sharing during the discovery and
+ decreases code size and duplication using the same code for service discovery.
+
+ - Implement the discovery service in the RPC layer for efficiency reasons.
+ - Implement service identity discovery for all services.
+ - Remove the encoding type entity and use service UUIDs to represent the serialization type.
+ - Service property discovery is to be implemented in the future.
+
+- Add support for the Corstone-1000 platform. For more information about this platform please see: `Corstone-1000 product homepage`_
+
+- SPs now indicate support of :term:`Normal World` interrupt preemption capability in their SP manifest and allow the SPMC to enable
+ preemption if possible. This removes NWd interrupts being disabled for long periods due to long service calls.
+
+- Add support for the Armv8-A CRC32 feature for :term:`Secure World` and :term:`Normal World` components.
+
+- Extend FF-A support with:
+
+ - FF-A v1.1 boot protocol between the SPM and SPs.
+ - FF-A v1.2 FFA_CONSOLE_LOG call. This allows SPs to emit log messages in an SPMC agonistic way.
+
+- Improve the build system to allow setting the build steps of external components to be verbose.
+
+- Add support for runtime (dynamic) psa-acs test case configuration.
+
+Updated external components
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- MbedTLS version integration into the Crypto service is updated to v3.4.0.
+- The PSA Arch test is updated to version `74dc6646ff594e131a726a5305aba77bac30eceb`.
+
+Breaking changes
+^^^^^^^^^^^^^^^^
+
+- The new RPC ABI is not backwards compatible and needs recent version of all depending components.
+
+Resolved issues
^^^^^^^^^^^^^^^
-None.
-Deprecations
-^^^^^^^^^^^^
-None.
+- The new RPC version allows having multiple shared memory regions between endpoints. This allows each NWd client
+ running in Linux user-space to use a dedicated buffer.
+
+Known limitations
+^^^^^^^^^^^^^^^^^
+
+ - Crypto key store partitioning by client is not yet supported. This means multiple clients running at the same FF-A
+ endpoint use a shared key space.
+ - The full firmware update process implementation and testing is work-in-progress. The FWU process relies on the
+ cooperation of multiple FW components owned by multiple FW projects. Some 3rd party components do not implement the
+ needed features yet and thus, the FWU service was validated in "isolation" and exercised by TS test on the FVP
+ platform and on the host PC only.
+ - Service property discovery is not implemented yet.
+ - Discovering the maximum payload size of a service is not supported yet and buffer sizes are hardcoded.
+
+Version 1.0.0-Beta
+------------------
+
+The first tagged release of the project.
+
+Feature Highlights
+^^^^^^^^^^^^^^^^^^
+
+The project supports the following services:
+
+ - Secure Storage
+ - Crypto
+ - Initial Attestation
+ - Smm Variable
+
+Services may be accessed using client components that implement "`Psacertified v1.0 APIs`_". The project includes deployments
+that integrate `PSA API certification tests`_ with API clients to facilitate end-to-end PSA certification testing.
+
+Known limitations
+'''''''''''''''''
+
+ - Crypto key store partitioning by client is not yet supported.
+ - Discovery support is only currently integrated into the Crypto service provider. In case of services not supporting
+ this feature yet, communication parameters (e.g. maximum buffer size) and supported feature set needs to be hardcode
+ to the service provider and service client.
+
+Supported Trusted Environments
+''''''''''''''''''''''''''''''
+
+In the default configuration each service is deployed to a dedicated FF-A Secure Partition and executes isolated.
+Service implementations are platform, trusted environment and service deployment agonistic. With appropriate enablement
+work services can be enabled to work in any combination of these.
+
+The reference integration uses the SPMC implemented in OP-TEE OS to manage TS SPs. This release supports `OP-TEE v3.19`_.
+
+Supported Integration Systems
+'''''''''''''''''''''''''''''
+
+The reference solution uses the OP-TEE integration methodology. This relies on the google repo tool for high-level dependency
+management and a set of makefiles to capture the build configuration information. For details please refer to
+`OP-TEE git repo documentation`_.
+
+The project is officially enabled in `Yocto meta-arm`_.
+
+Supported Target Platforms
+''''''''''''''''''''''''''
+
+The only reference platform supported by this release is the `AEM FVP`_ build using the OP-TEE integration method.
+
+Known limitations:
+
+ - Non-volatile backend secure storage is not currently provided.
+
+Test Report
+^^^^^^^^^^^
+
+Please find the Test Report covering this release in the `tf.org wiki`_.
+
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+.. _`FF-A Specification v1.0`: https://developer.arm.com/documentation/den0077/a
+.. _`Psacertified v1.0 APIs`: https://www.psacertified.org/development-resources/building-in-security/specifications-implementations/
+.. _`OP-TEE v3.19`: https://github.com/OP-TEE/optee_os/tree/3.19.0
+.. _`Yocto meta-arm` : https://gitlab.oss.arm.com/engineering/yocto/meta-arm/-/tree/master/meta-arm/recipes-security/trusted-services
+.. _`tf.org wiki`: https://developer.trustedfirmware.org/w/trusted-services/test-reports/v1.0.0-beta/
+.. _`AEM FVP`: https://developer.arm.com/-/media/Files/downloads/ecosystem-models/FVP_Base_RevC-2xAEMvA_11.18_16_Linux64.tgz
+.. _`PSA API certification tests`: https://github.com/ARM-software/psa-arch-tests
+.. _`OP-TEE git repo documentation`: https://optee.readthedocs.io/en/latest/building/gits/build.html
+.. _`Corstone-1000 product homepage`: https://developer.arm.com/Processors/Corstone-1000
+.. _`Arm FWU-A specification`: https://developer.arm.com/documentation/den0118
+
+*Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/project/coding-guidelines.rst b/docs/project/coding-guidelines.rst
index 3090aa489..cc5c18e4c 100644
--- a/docs/project/coding-guidelines.rst
+++ b/docs/project/coding-guidelines.rst
@@ -1,26 +1,23 @@
Coding Style & Guidelines
=========================
-The following sections contain |TS| coding guidelines. They are continually evolving and should not be considered "set
-in stone". Feel free to question them and provide feedback.
-
-The |TS| project uses multiple "domains" (textual content types, like programming languages) and each defines its own
-rules.
+The following sections contain |TS| coding guidelines for different types of file. They are continually evolving
+and should not be considered "set in stone". Feel free to question them and provide feedback.
To help configuring text editors the project comes with "`EditorConfig`_" file(s). (:download:`../../.editorconfig`).
-Shared rules
+Common Rules
------------
-The following rules are common for all domains, except where noted otherwise:
+The following rules are common for all types of text file, except where noted otherwise:
#. Files shall be **UTF-8** encoded.
#. Use **Unix** style line endings (``LF`` character)
#. The primary language of the project is English. All comments and documentation must be in this language.
#. Trailing whitespace is not welcome, please trim these.
-C Domain
---------
+C Rules
+-------
C source code rules are base on the *Linux Coding Style* (See: |LCS|). The following deviations apply:
@@ -33,13 +30,23 @@ C source code rules are base on the *Linux Coding Style* (See: |LCS|). The follo
alphabetically in the above two groups.
#. All variables must be initialized.
-Boring stuff is not for smart people and the project uses the `Uncrustify`_ code beautifier to easy formatting the
-source. (See :download:`../../.uncrustify.cfg`)
+C source files should include a copyright and license comment block at the head of each file. Here is an example::
-CMake domain
-------------
+ /*
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+Boring stuff is not for smart people and the project uses the `Clang-Format`_ code beautifier to easy formatting the
+source. (See :download:`../../.clang-format`)
-11. CMake file names use `CamelCase`_ style.
+CMake Rules
+-----------
+
+Cmake files (e.g. CMakeLists.txt and .cmake) should conform to the following rules:
+
+1. CMake file names use `CamelCase`_ style.
#. Indent with tabs and otherwise use spaces. Use 4 spaces for tab size.
#. Use LF as line end in CMake files.
#. Remove trailing whitespace.
@@ -53,10 +60,17 @@ CMake domain
#. Use the Sphinx CMake domain for in-line documentation of CMake scripts. For details please refer to the
`CMake Documentation`_.
-.. todo:: Explain CMake return values and parent scope concept in more detail.
+Each file should include a copyright and license comment block at the head of each file. Here is an example::
+
+ #-------------------------------------------------------------------------------
+ # Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ #
+ # SPDX-License-Identifier: BSD-3-Clause
+ #
+ #-------------------------------------------------------------------------------
-Restructured Text Domain
-------------------------
+Restructured Text Rules
+-----------------------
Please refer to :doc:`/developer/writing-documentation`.
@@ -66,8 +80,8 @@ Please refer to :doc:`/developer/writing-documentation`.
.. _`snake_case`: https://en.wikipedia.org/wiki/Snake_case
.. _`CMake Documentation`: https://github.com/Kitware/CMake/blob/master/Help/dev/documentation.rst
.. _`EditorConfig`: https://editorconfig.org/
-.. _`Uncrustify`: https://github.com/uncrustify/uncrustify
+.. _`Clang-Format`: https://clang.llvm.org/docs/ClangFormat.html
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/project/contributing.rst b/docs/project/contributing.rst
index d9760d9f1..5d8cb8fa9 100644
--- a/docs/project/contributing.rst
+++ b/docs/project/contributing.rst
@@ -1,6 +1,10 @@
Contributing
============
+Reporting Security Issues
+-------------------------
+
+Please follow the directions of the `Trusted Firmware Security Center`_
Getting Started
---------------
@@ -9,7 +13,6 @@ Getting Started
- Send an email to the |TS_MAIL_LIST| about your work. This gives everyone
visibility of whether others are working on something similar.
- Clone the |TS_REPO| on your own machine.
-- Create a local topic branch based on ``main`` branch of the |TS_REPO|.
Making Changes
--------------
@@ -23,18 +26,18 @@ Making Changes
- Make sure your commit messages are in the proper format. Please keel the 50/72 rule (for details see `Tim Popes blog entry`_.)
- Where appropriate, please update the documentation.
- - Consider whether the this document or other in-source documentation
- needs updating.
+ - Consider which documents or other in-source documentation needs updating.
- Ensure that each changed file has the correct copyright and license information. Files that entirely consist of
contributions to this project should have a copyright notice and BSD-3-Clause SPDX license identifier of the form
- as shown in :ref:`license`. Files that contain changes to imported Third Party IP files should retain their
- original copyright and license notices. For significant contributions you may add your own copyright notice in
- following format::
+ as shown in :ref:`license`. Example copyright and license comment blocks are shown in :ref:`Coding Style & Guidelines`.
+ Files that contain changes to imported Third Party IP files should retain their original copyright and license
+ notices. For significant contributions you may add your own copyright notice in following format::
Portions copyright (c) [XXXX-]YYYY, <OWNER>. All rights reserved.
where XXXX is the year of first contribution (if different to YYYY) and YYYY is the year of most recent
contribution. *<OWNER>* is your name or your company name.
+ - For any change, ensure that YYYY is updated if a contribution is made in a year more recent than the previous YYYY.
- If you are submitting new files that you intend to be the technical sub-maintainer for (for example, a new platform
port), then also update the :ref:`maintainers` file.
- For topics with multiple commits, you should make all documentation changes (and nothing else) in the last commit
@@ -81,8 +84,8 @@ Submitting Changes
.. _Gerrit Signed-off-by Lines guidelines: https://review.trustedfirmware.org/Documentation/user-signedoffby.html
.. _Gerrit Change-Ids documentation: https://review.trustedfirmware.org/Documentation/user-changeid.html
.. _`Tim Popes blog entry`: https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
+.. _`Trusted Firmware Security Center`: https://developer.trustedfirmware.org/w/collaboration/security_center/
-
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/project/glossary.rst b/docs/project/glossary.rst
index 74356c06a..ec79dbc4d 100644
--- a/docs/project/glossary.rst
+++ b/docs/project/glossary.rst
@@ -29,16 +29,79 @@ You can find additional definitions in the `Arm Glossary`_.
FF-A
`Firmware Framework for A`_
+ Normal World
+ The rich execution environment running the "business logic" of the device. NWd is separated by hardware
+ technology (e.g. see :term:`TrustZone`) from components which are managing sensitive information. See
+ :term:`Secure World`.
+
+ NWd
+ See :term:`Normal World`.
+
+ Secure World
+ Hardware isolated execution environment executing specially crafted software managing sensitive data. On Arm
+ devices :term:`TrustZone` technology can be used to implement the needed isolation.
+
+ SWd
+ See :term:`Secure World`.
+
+ TEE
+ Trusted Execution Environment. An SPE implemented using TrustZone.
+
+ TrustZone
+ Hardware assisted isolation technology built into arm CPUs. See `TrustZone for Cortex-A`_.
+
+ SPE
+ See :term:`Secure Processing Environment`.
+
+ Secure Processing Environment
+ An isolated environment to execute software images backed by a specific set of hardware and arm architecture
+ features. The aim of isolation is to protect sensitive workloads and their assets.
+
+ SP
+ see :term:`Secure Partition`
+
+ Secure Partition
+ Secure Partition is a compartment to execute a software image isolated from other images. Isolation can be logical
+ or physical based on if physical address range isolation is involved or not. See :term:`Physical SP` and :term:`Logical SP`.
+
+ An SP may host a single or multiple services.
+
+ Physical SP
+ A Secure Partition which executes a software image in and isolated physical address space.
+
+ Logical SP
+ A Secure Partition which executes a software image isolated buy without physical address space isolation.
+
+ SPM
+ See :term:`Secure Partition Manager`.
+
+ Secure Partition Manager
+ A component responsible for creating and managing the physical isolation boundary of an :term:`SP` in the SWd. It
+ is built from two sub-components the :term:`Secure Partition Manager Dispatcher` and the
+ :term:`Secure Partition Manager Core`.
+
+ Secure Partition Manager Dispatcher
+ The SPM component responsible for SPMC initialization boot-time, and forwarding FF-A calls run-time between SPs
+ and between SPs and the SPMC.
+
+ Secure Partition Manager Core
+ A component responsible for SP initialization and isolation at boot-time, inter partition isolation at run-time,
+ inter-partition communication at run-time.
+
+ Secure Enclave
+ An isolated hardware subsystem focusing on security related operations. The subsystem may include hardware
+ peripherals and one or more processing elements. As an example see the `Arm SSE-700`_ subsystem.
--------------
-.. _`Arm Glossary`: https://developer.arm.com/support/arm-glossary
+.. _`Arm Glossary`: https://developer.arm.com/documentation/aeg0014
.. _`Linux Coding Style`: https://www.kernel.org/doc/html/v4.10/process/coding-style.html
.. _`Arm C language extensions`: https://developer.arm.com/documentation/101028/0012/?lang=en
.. _`Platforn Security Arhitecture`: https://developer.arm.com/architectures/security-architectures/platform-security-architecture
.. _`Firmware Framework for A`: https://developer.arm.com/docs/den0077/latest
+.. _`TrustZone for Cortex-A`: https://www.arm.com/technologies/trustzone-for-cortex-a
+.. _`Arm SSE-700`: https://developer.arm.com/documentation/101418/0100/Overview/About-SSE-700
-
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/project/index.rst b/docs/project/index.rst
index 21f1d0f57..d7a4b4bb5 100644
--- a/docs/project/index.rst
+++ b/docs/project/index.rst
@@ -1,4 +1,4 @@
-About the project
+About the Project
=================
.. toctree::
@@ -12,10 +12,12 @@ About the project
license
maintainers
versioning_policy
- todo
+ version_control
+ quality-assurance/index
+ releases
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/project/quality-assurance/index.rst b/docs/project/quality-assurance/index.rst
new file mode 100644
index 000000000..775fce9fb
--- /dev/null
+++ b/docs/project/quality-assurance/index.rst
@@ -0,0 +1,30 @@
+Quality Assurance
+=================
+
+This section covers quality definition of the project, efforts the project is making to ensure the quality level of the
+products meet expectations.
+
+The primary products of this project are the :ref:`Deployments` building :ref:`Secure Partition Images` and `Libraries`.
+There are secondary products like:
+
+ - build scripts
+ - test automation scripts
+ - documentation
+ - various processes
+ - etc...
+
+Quality Assurance of secondary products happens at a "best effort" basis. The project will try to keep these healthy,
+but quality definition of these may aim lower or may even be lacking.
+
+.. toctree::
+ :maxdepth: 1
+
+ ./verification-strategy
+ ./verification-methodology
+ ./verification-plan
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/docs/project/quality-assurance/verification-methodology.rst b/docs/project/quality-assurance/verification-methodology.rst
new file mode 100644
index 000000000..f68401d2e
--- /dev/null
+++ b/docs/project/quality-assurance/verification-methodology.rst
@@ -0,0 +1,71 @@
+Verification methodology
+========================
+
+This page discusses discusses verification tools and techniques used by the project.
+
+
+Static Checks
+-------------
+
+This verification step checks quality by examining the source code. The project currently uses two tools which are
+discussed in the chapters below.
+
+Checkpatch
+''''''''''
+
+`Checkpatch`_ is a tool developed and maintained by the Linux Kernel community. It can look for errors related to:
+
+ - C and C++ coding style
+ - spelling mistakes
+ - git commit message formatting
+
+Please find the configuration of this tool in the :download:`TS repository.<../../../.checkpatch>`
+
+Cppcheck tool
+'''''''''''''
+
+`CppCheck`_ is a C/C++ static analysis tool. It can detect code depending on implementation defined behavior, and
+dangerous coding constructs and thus it verifies coding guidelines.
+
+Please find the configuration of this tool in the :download:`TS repository.<../../../.cppcheck>`
+
+Build verification
+------------------
+
+The :ref:`Build test runner` captures reference build configurations for all TS build products and can be used to verify
+these.
+
+Runtime verification
+--------------------
+
+During the runtime versification step various test and demo executables are executed on the host PC and/or on target
+platforms.
+
+Tests are targeting three different environment types:
+
+ - ``arm-linux``: test executables to be run from Linux user-space on the target.
+ - ``pc-linux``: executables to run on the host PC. These tests have a lower verification level, as the binary is likely
+ not running on an arm target. Portability issues in the source may hide error or trigger false alarms. In turn
+ this type of test is cheap,
+ - ``sp`` and ``opteesp``: test executables targeting these environments run in the SWd and server as:
+
+ - test payloads to help exercise trusted services
+ - test payload to help platform porting
+
+Each of these test applications manifest as a "deployment" in trusted services. For more details please see the
+:ref:`Deployments` section.
+
+Compliance testing
+''''''''''''''''''
+
+The project hosts deployment helping compliance testing. For more information please refer to
+:ref:`Platform Certification`.
+
+------------------
+
+.. _`Checkpatch`: https://docs.kernel.org/dev-tools/checkpatch.html
+.. _`CppCheck`: https://cppcheck.sourceforge.io/
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/project/quality-assurance/verification-plan.rst b/docs/project/quality-assurance/verification-plan.rst
new file mode 100644
index 000000000..3e67f4352
--- /dev/null
+++ b/docs/project/quality-assurance/verification-plan.rst
@@ -0,0 +1,37 @@
+Verification Plan
+=================
+
+This document describes when and by whom verification steps are to be executed. Since this is an open-source project
+maintained by an open community, each contributor is expected to participate.
+
+Verification during development
+-------------------------------
+
+When changing existing code, or adding new code, the developer is expected to:
+
+ - run static checks to guard "clean code".
+ - execute runtime tests on the host machine to ensure features not changed are behaving as before. Verification
+ efforts targeting regression may be limited based on the expected effects of the change.
+ - extend unit and component tests to cover changes
+
+Verification during code review
+-------------------------------
+
+The code review covers all aspects of a change, including design and implementation. This includes running static checks
+and runtime tests. The reviewers are expected to check if tests are extended as needed.
+
+Verification efforts of a review may be limited to lower costs, based on the expected effects of the change.
+
+Guarding "main"
+---------------
+
+All commits of the integration branch shall be verified using the full verification set-up. This verification shall aim
+for achieving the highest quality level and shall not make compromises. A change becomes ready to get merged to "main"
+after passing the tests.
+
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/docs/project/quality-assurance/verification-strategy.rst b/docs/project/quality-assurance/verification-strategy.rst
new file mode 100644
index 000000000..db4a03d07
--- /dev/null
+++ b/docs/project/quality-assurance/verification-strategy.rst
@@ -0,0 +1,98 @@
+Verification Strategy
+=====================
+
+This page describes verification from a high level concept perspective.
+
+In this context ``source code`` has a wider scope and may mean any text content produced by humans and processed by
+other humans or tools. Examples: C/C++ source code, reST documents, build scripts, etc...
+
+Clean Code
+----------
+
+Clean code aims to counterfeit issues discussed in the following sub-chapters.
+
+Code Readability
+''''''''''''''''
+
+Expressing ideas in a machine readable formats is complicated, and each developer may have a different taste or
+different preferences on how source code should be formatted. Some people may find a specific kind of formatting easier
+to understand than others. If the source code does not follow a consistent look and feel, human processing of the text
+may become error prone. This undermines effectiveness of co-operation and code-review, and may lead to incorrect code.
+The project defines coding style rules to counterfeit these problems. For detail please refer to :ref:`Coding Style &
+Guidelines`
+
+Undefined and Implementation Defined Behavior
+'''''''''''''''''''''''''''''''''''''''''''''
+
+The "standard" defining how to process a specific source code type, may leave some processing behavior to the tool
+to be defined, or allow the tool to behave in an undefined way. Coding constructs relying on such behavior are to be
+avoided, or used in a well defined way. This adds robustness and helps avoiding errors due to using different version
+of the same tool, or different implementations.
+
+The project defines coding guidelines to counterfeit these problems. For detail please refer to
+:ref:`Coding Style & Guidelines`
+
+Security
+''''''''
+
+Security is a complex topic affecting all steps of the development process. Incorrect code may lead to security issues
+and thus "Clean Code" has a vital role in implementing secure software.
+
+Runtime Testing
+---------------
+
+Runtime testing focuses of verifying the behavior of one or multiple build products built from source code. This can be
+done at multiple levels and in multiple execution environment.
+
+
+Unit Test
+'''''''''
+
+Unit tests aim to verify if the internal operation of a module matches the developers expectation. It helps covering all
+code execution paths, and to give confidence on correct operation when code needs to be refactored. Unit tests serve as
+a kind of documentation capturing the expected usage of the code.
+
+Unit-testing allays happen on the "host PC"
+
+Component Test
+''''''''''''''
+
+Component tests aim to verify the API (and ABI) of a component is matching expectations. Components are tested in
+isolation, where the exported APIs are exercised by these code, and APIs the component depends on are implemented by
+test doubles.
+
+System Test
+'''''''''''
+
+System test verifies correct operation of a set of modules configured to fulfill the requirements of a use-case. For TS
+this usually means testing and end-to-end setup on a specific target platform.
+
+Balancing Costs vs Quality
+''''''''''''''''''''''''''
+
+Executing build products on target platforms may have high costs in terms of time, complexity and availability and in
+turn it gives the hights confidence in verification results, or the best quality. In the development phase it may be
+desired to some level of this confidence for lower costs. For this purpose the project defines two main test
+set-up types based on the balance choice between cost and quality.
+
+Testing on a Target Platform
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this environment tests are executed on a target platform. Emulators (e.g. QEMU, FVP) from this aspect are treated
+like targets implemented in silicon.
+
+Testing on the Host Machine
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this environment test executables are compiled to execute as a "standard" user-space application running on the
+machine "hosting" the development activity. In most cases these machines are based on a different architecture that the
+ones the project is targeting (e.g. x86-64 vs aarch64). This means this environment relies on the assumption that code
+is portable and behaves architecture and compiler independent. This puts limitations on the features which can be tested
+and lower the confidence level of test output. In turn executing tests int his environment is simple and gives very good
+scalability options.
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/docs/project/releases.rst b/docs/project/releases.rst
new file mode 100644
index 000000000..e8f38cbba
--- /dev/null
+++ b/docs/project/releases.rst
@@ -0,0 +1,56 @@
+Releases
+========
+
+The release is a well documented and identifiable "quality snapshot" of the products the project is developing. It helps
+adopters by providing reference points and understanding differences between these.
+
+Due to the :ref:`Version Control` policy implemented, each commit on the "main" branch has a source code and runtime
+quality level as a release. The release in addition to that ads extra documentation of changes in form of the
+:ref:`Change Log & Release Notes`
+
+Cadence
+-------
+
+There is no fixed release cadence defined yet.
+
+Release procedure
+=================
+
+``DR`` below stands for "Day of Release".
+
+.. list-table:: Release steps
+ :header-rows: 1
+
+ * - Time
+ - Task
+ * - ``DR``-3w
+ -
+ - Send notification to |TS_MAIL_LIST| about upcoming release.
+ - Release note update starts.
+ - Platform maintainers prepare for testing their platforms.
+ * - ``DR``-1w
+ -
+ - A release PR is created updating the release ID and release notes.
+ - "integration" branch is frozen and "main" branch is updated if needed.
+ - "main" branch is tagged with `_rc0` tag to mark start of release testing.
+ - Maintainers start release testing.
+ - Platform maintainers start release testing their platforms.
+ * - ``DR``
+ -
+ - Release notes is finalized.
+ - Release PR gets merged.
+ - "main" branch is updated.
+ - "main" branch is tagged.
+ - Release announcement is sent to |TS_MAIL_LIST|.
+
+Errors discovered during testing will break the release process. Fixes need to be made and merged as usual, and release
+testing to be restarted with including applying a new ``_rc<x>`` tag, where ``<x>`` is a monotonic counter.
+
+If fixing the encountered errors takes long, the release is either aborted and postponed, or the defects are captured in
+the release notes under the "known issues" section.
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/docs/project/todo.rst b/docs/project/todo.rst
deleted file mode 100644
index 1739eabcd..000000000
--- a/docs/project/todo.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-TODO list
-=========
-
-This file collects information on planned future changes and issues to be
-addressed. For managing the TODO list below, the `Sphinx TODO extension`_ is
-used.
-
-.. todo:: Find a solution to make the rendering of TODO entries less intrusive
- at their original location.
-
-List of TODO entries in the project
------------------------------------
-
-.. todolist::
-
---------------
-
-.. _`Sphinx TODO extension`: https://www.sphinx-doc.org/en/master/usage/extensions/todo.html
-
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
-
-SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/docs/project/version_control.rst b/docs/project/version_control.rst
new file mode 100644
index 000000000..ebcfc6f0b
--- /dev/null
+++ b/docs/project/version_control.rst
@@ -0,0 +1,68 @@
+Version Control
+===============
+
+Version control is about tracking and managing changes to text files including source-code, scripts, configuration
+files and documentation.
+
+The project uses the `Git version control system`_ and Gerrit as the code review and access restriction enforcement
+solution. Although git is a distributed version control system the project uses a "centralized" approach. The main
+repositories can be found at https://trustedfirmware.org, where two WEB UIs can be found:
+
+ - a `cgit instance`_ allowing browse and clone the repositories
+ - and a `Gerrit instance`_ for contribution and code review purposes.
+
+Currently the project has a single repository hosting the source-code:
+https://git.trustedfirmware.org/TS/trusted-services.git/
+
+Branching Strategy
+------------------
+
+The branching strategy is built around a "quality" based flow of changes.
+
+Each change starts targeting an "integration" branch either as a "standalone" change or as a topic. Changes landing on
+integrations are expected to be "independent" (properly build and working without depending on other changes).
+Validation efforts of the changes my have limited focus based on the expected effect of the change. This allows
+balancing validation costs to pay during reviews.
+
+All change landing on the integration branch will get trough full validation. When passing all quality checks, the
+change can be merged to a "main" branch. All changes on the main branch are expected to fulfill all quality requirements
+and to pass full validation.
+
+The default name of the "integration" branch is ``integration`` and the default name of the "main" branch is ``main``.
+For special purposes (e.g. long term support, hosting a special version, etc...) other branches acting as "integration"
+and "main" can be defined.
+
+Sandbox branches
+----------------
+
+For prototyping purposes the project allows using "sandbox" branches. Changes on these branches are free to lower
+quality expectations as needed. Sandbox branches are to be created under ``sandbox/<username>/`` namespace
+(e.g. ``sandbox/gyoszi01/static-init-prototype``).
+
+Topic branches
+--------------
+
+For large changes or changes expected to have a longer development time "topic" branches can be used. Topic branches are
+to be created under the ``topics/<username>/<some name>`` namespace. If multiple developers are co-developing a feature
+``<username>`` is expect to be the lead developer.
+
+Review vs quality
+-----------------
+
+As discussed above all commits on the "integration" branch must properly build and work independent of other changes.
+This may result in large commits, which would make code reviews difficult. To help the code review, large changes should
+be split to small steps, each implementing a single logical step needed for the full change. To remove the conflict
+between quality expectation requiring large and review requiring small commits, topic branches shall be used. Large
+changes are to be split up to small steps and target a topic branch first. This way reviewers can check small changes,
+and only the tip of the topic branch is to pass build and runtime tests.
+
+.. _`cgit instance`: https://git.trustedfirmware.org/
+.. _`Gerrit instance`: https://review.trustedfirmware.org/
+
+-------------
+
+.. _`Git version control system`: https://git-scm.com/
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/docs/project/versioning_policy.rst b/docs/project/versioning_policy.rst
index d57057fbe..c176db324 100644
--- a/docs/project/versioning_policy.rst
+++ b/docs/project/versioning_policy.rst
@@ -5,25 +5,34 @@ This document captures information about the version identifier used by the
project. It tells the meaning of each part, where the version information is
captured and how it is managed.
-Summary
--------
+Format of version IDs
+---------------------
The version identifier identifies the feature set supported by a specific
release, and captures compatibility information to other releases.
This project uses "Semantic Versioning", for details please refer to |SEMVER|.
-In general the version number is constructed from three numbers. The `MAJOR`
-number is changed when incompatible API changes are introduced, the `MINOR`
-version when you functionality is added in a backward compatible manner, and
-the `PATCH` version when backwards compatible bug fixes are added.
+The version number is constructed from three numbers, and an optional
+pre-release identifier. The `MAJOR` number is changed when incompatible API
+changes are introduced, the `MINOR` version when new functionality is added in a
+backward compatible manner, and the `PATCH` version when backwards compatible
+bug fixes are added. The pre-release identifier is appended after the numbers
+separated with a ``-`` and can be the string ``alpha`` or ``beta``.
-Each release will get a unique release id assigned. When a release is made, the
+Each release will get a unique version id assigned. When a release is made, the
version number will get incremented in accordance with the compatibility rules
mentioned above.
-This project is only using the core version and will not use pre-release or
-build specific metadata extension.
+Version ID hierarchy
+--------------------
+
+The project hosts multiple components which can be used separately and thus need
+compatibility information expressed independently. Such components get a
+dedicated version ID. Examples are :ref:`libs-libsp` and :ref:`libs-libts`.
+
+Components are never released standalone but only part of a TS release. In that
+sense a set of independent component version IDs are assigned to a TS release ID.
Storage and format
------------------
@@ -42,6 +51,6 @@ The version number of each release will be stored at two locations:
.. _`Semantic Versioning`: https://semver.org/spec/v2.0.0.html
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/quickstart/index.rst b/docs/quickstart/index.rst
new file mode 100644
index 000000000..73a36607b
--- /dev/null
+++ b/docs/quickstart/index.rst
@@ -0,0 +1,18 @@
+Quick Start Guides
+==================
+
+The following quick start guides provide step-by-step instructions for performing common tasks when
+working with the Trusted Services project.
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents:
+
+ pc-testing
+ optee-testing
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/quickstart/optee-testing.rst b/docs/quickstart/optee-testing.rst
new file mode 100644
index 000000000..7eccf7ab9
--- /dev/null
+++ b/docs/quickstart/optee-testing.rst
@@ -0,0 +1,92 @@
+Build and run tests on OP-TEE reference integration for FVP
+===========================================================
+
+The Linux based build maintained by the OP-TEE project is used as the reference integration for testing
+trusted service deployments on a simulated hardware platform. Service providers deployed within secure partitions
+are tested using test executables that run as user-space programs under Linux. Test cases interact with trusted
+service providers using standard service access protocols, carried by FF-A based messages.
+
+The test executables most often used for service level testing on hardware platforms are:
+
+ - *ts-service-test* - contains a set of service-level end-to-end tests. Discovers and communicates
+ with service providers using libts.
+ - *psa-api-test* - PSA functional API conformance tests (from external project). Also uses libts.
+
+This method uses the makefiles from the ``op-tee/build`` repository.
+
+
+Before you start
+----------------
+
+Before attempting to run tests on the FVP simulation, the OP-TEE reference integration needs to be
+built and run. Read the following guides to understand how to do this:
+
+ - OP-TEE build and run instructions, see:
+ :ref:`Deploying trusted services in S-EL0 Secure Partitions under OP-TEE`
+
+ - Instructions for loading and running user-space programs on FVP:
+ :ref:`Running user-space programs on FVP`
+
+
+Build the Linux application binaries
+------------------------------------
+
+From the root directory of the workspace, enter the following to build the test applications::
+
+ make -C build ffa-test-all
+
+
+Run *ts-service-test*
+---------------------
+
+From the root directory of the workspace, enter::
+
+ FVP_PATH=../Base_RevC_AEMvA_pkg/models/Linux64_GCC-9.3 make -C build run-only
+
+Once it boots to the login prompt, log in as root and from the FVP terminal, enter::
+
+ cd /mnt/host
+ cp -vat /usr out/ts-install/arm-linux/lib out/ts-install/arm-linux/bin
+ out/linux-arm-ffa-tee/load_module.sh
+ out/linux-arm-ffa-user/load_module.sh
+ ts-service-test -v
+
+Use the same flow for other user-space programs. Check the output of the ``cp`` command executed to see
+executables copied under ``/usr/bin``.
+
+.. _build-spmc-tests:
+
+Build SPMC tests
+----------------
+
+Trusted Services includes S-EL0 tests SPs for validating the SPMC's behavior by invoking various FF-A interfaces. These tests
+require OP-TEE's `xtest`_ for starting them from the normal world. ``xtest`` uses ``linux-arm-ffa-user`` for accessing the
+FF-A layer. Building the SPMC tests uses the same build system but with the ``SPMC_TEST=y`` configuration::
+
+ make -C build SPMC_TEST=y all
+
+.. note::
+ This build configuration only contains the SPMC test SPs and it does not include any of the :ref:`Services`.
+
+See :ref:`OP-TEE SPMC tests` for further information.
+
+Run SPMC tests
+--------------
+
+From the root directory of the workspace, enter::
+
+ FVP_PATH=../Base_RevC_AEMvA_pkg/models/Linux64_GCC-9.3 make -C build run-only
+
+Once it boots to the login prompt, log in as root and from the FVP terminal, enter::
+
+ cd /mnt/host
+ out/linux-arm-ffa-user/load_module.sh
+ xtest -t ffa_spmc
+
+--------------
+
+.. _`xtest`: https://optee.readthedocs.io/en/latest/building/gits/optee_test.html
+
+*Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/quickstart/pc-testing.rst b/docs/quickstart/pc-testing.rst
new file mode 100644
index 000000000..295273df4
--- /dev/null
+++ b/docs/quickstart/pc-testing.rst
@@ -0,0 +1,78 @@
+Build and run PC based tests
+============================
+
+Many components within the Trusted Services project may be built and tested within a native PC environment.
+PC based testing is an important part of the development flow and can provide a straight-forward way to check
+for regressions and debug problems. PC based tests range from small unit tests up to end-to-end service tests.
+All test cases in the Trusted Services project are written for the CppUTest test framework.
+
+The test executables most often used for PC based testing of Trusted Services components are:
+
+ - *component-test* - a PC executable that runs many component level tests.
+ - *ts-service-test* - contains a set of service-level end-to-end tests. For PC build, service providers
+ are included in the libts library.
+ - *psa-api-test* - PSA functional API conformance tests (from external project).
+
+
+Before you start
+----------------
+Before attempting to run any builds, ensure that all necessary tools are installed. See: :ref:`Software Requirements`
+
+
+Build and run *component-test*
+------------------------------
+
+From the root directory of the checked-out TS project, enter the following::
+
+ cmake -B build-ct -S deployments/component-test/linux-pc
+ make -C build-ct install
+ build-ct/install/linux-pc/bin/component-test -v
+
+
+Build and run *ts-service-test*
+-------------------------------
+
+From the root directory of the checked-out TS project, enter the following::
+
+ cmake -B build-ts -S deployments/ts-service-test/linux-pc
+ make -C build-ts install
+ LD_PRELOAD=build-ts/install/linux-pc/lib/libts.so build-ts/install/linux-pc/bin/ts-service-test -v
+
+Build and run *psa-api-test*
+----------------------------
+Tests for each API are built as separate executables. Test are available for the following APIs::
+
+ crypto
+ initial_attestation
+ internal_trusted_storage
+ protected_storage
+
+To build and run tests for the Crypto API, enter the following (use the same flow for other APIs)::
+
+ cmake -B build-pa deployments/psa-api-test/crypto/linux-pc
+ make -C build-pa install
+ LD_PRELOAD=build-pa/install/linux-pc/lib/libts.so build-pa/install/linux-pc/bin/psa-crypto-api-test
+
+psa-api test binaries accept the listed command-line arguments:
+
+=========== ====================================================================
+CL argument Description
+=========== ====================================================================
+-v verbose mode
+-h print supported arguments
+-l print a list of all the available tests
+-t run only the listed tests with 'test\_' prefix and semicolon postfix
+ e.g: "-t test_201;test_205;test_260;"
+=========== ====================================================================
+
+More information
+----------------
+For more information about deployments and building, see: :ref:`Build Instructions`
+
+PSA functional API conformance tests git location: https://github.com/ARM-software/psa-arch-tests.git
+
+--------------
+
+*Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 7b7562c7f..516a46c79 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,12 +1,14 @@
#
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Python dependencies for building the documentation.
-Sphinx==2.3.1
-sphinx-rtd-theme==0.4.3
-sphinxcontrib-moderncmakedomain==3.13
-sphinxcontrib-plantuml==0.18
+Sphinx==4.5
+sphinx-rtd-theme==1.0.0
+sphinxcontrib-moderncmakedomain==3.21.4
+sphinxcontrib-plantuml==0.23
+Jinja2==2.11.3
+markupsafe==2.0.1
diff --git a/docs/security/generic-data-flow.graphml b/docs/security/generic-data-flow.graphml
new file mode 100644
index 000000000..5d96f0047
--- /dev/null
+++ b/docs/security/generic-data-flow.graphml
@@ -0,0 +1,500 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+ <!--Created by yEd 3.21.1-->
+ <key attr.name="Description" attr.type="string" for="graph" id="d0"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key for="graphml" id="d7" yfiles.type="resources"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d0" xml:space="preserve"><![CDATA[Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+SPDX-License-Identifier: BSD-3-Clause
+
+Generic threat modell of a Trusted Service.
+]]></data>
+ <node id="n0">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="12.496800000000093" width="167.67999999999955" x="999.8343945312489" y="457.4259263183566"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#FF0000" raised="false" type="dashed" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.0078125" x="4.0" xml:space="preserve" y="-3.1021859374999394">TB3<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="-0.5" labelRatioY="0.0" nodeRatioX="-0.5" nodeRatioY="1.1102230246251565E-15" offsetX="4.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="564.0099999999994" width="12.179999999999382" x="583.593507385258" y="200.62211367188718"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#FF0000" raised="false" type="dashed" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.0078125" x="-6.913906250000309" xml:space="preserve" y="18.910353412126142">TB1<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="-0.4664715990636227" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="315.409166121018" width="12.179999999999325" x="857.1073454715039" y="398.44871367188716"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#FF0000" raised="false" type="dashed" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.0078125" x="-6.913906250000309" xml:space="preserve" y="165.94207995215538">TB2<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="2.3314683517128287E-15" nodeRatioY="0.05576275111294027" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="342.98698105468577" width="200.67999999999978" x="342.94159179687404" y="329.30920419922944"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="dotted" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="4.0" x="6.883049475401549" y="25.723656299968127">
+ <y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="-0.5" labelRatioY="-0.5" nodeRatioX="-0.46570136797188777" nodeRatioY="-0.42500107082528954" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="149.14062499999994" x="974.6586840820303" y="342.980075781258"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="98.037109375" x="25.5517578125" xml:space="preserve" y="16.6494140625">Trusted Service 1<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="149.14062499999994" x="974.6586840820304" y="631.9019579101412"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="98.037109375" x="25.551757812499886" xml:space="preserve" y="16.6494140625">Trusted Service 2<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n6">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="95.3709810546855" width="149.14062499999994" x="656.5949816894521" y="434.9416231445441"/>
+ <y:Fill color="#CCCCCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="30.00390625" x="59.568359375" xml:space="preserve" y="38.33490458984272">SPM<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n7">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="149.14062499999994" x="367.4203417968745" y="346.15949472657235"/>
+ <y:Fill color="#FFDD56" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="72.70703125" x="38.216796875" xml:space="preserve" y="16.6494140625">u-boot/EDK2<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n8">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="149.14062499999994" x="367.4203417968745" y="415.1892041992295"/>
+ <y:Fill color="#FFDD56" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="98.037109375" x="25.5517578125" xml:space="preserve" y="16.6494140625">Operating system<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n9">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="149.14062499999994" x="367.4203417968745" y="496.98920419922956"/>
+ <y:Fill color="#FFDD56" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="126.0625" x="11.5390625" xml:space="preserve" y="16.6494140625">User-space application<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n10">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="149.14062499999994" x="625.7735073852574" y="631.9019579101412"/>
+ <y:Fill color="#CCCCCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="79.345703125" x="34.8974609375" xml:space="preserve" y="16.6494140625">FF-A Manifest<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n11">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="124.88348205566643" x="981.027255554197" y="245.62007578125798"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="48.103515625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="110.716796875" x="7.083342590333245" xml:space="preserve" y="1.9482421875">Dedicated,
+Physically protected
+HW<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="parallelogram"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n12">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="149.14062499999994" x="691.3269164213868" y="554.353966953524"/>
+ <y:Fill color="#CCCCCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.37109375" x="44.884765625" xml:space="preserve" y="16.6494140625">Debug-log<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n13">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="24.360000000000014" width="103.80040771484022" x="1177.7967895507836" y="356.800075781258"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="88.03515625" x="7.882625732420138" xml:space="preserve" y="2.829414062500007">Peripheral IFC2<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="parallelogram"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n14">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="71.230075781258" width="157.46968750000036" x="1356.3271972656235" y="333.3650378906291"/>
+ <y:Fill color="#DDD55F" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="48.103515625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="131.39453125" x="13.03757812500021" xml:space="preserve" y="11.563280078128969">Dedicated,
+Not physically protected
+HW<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="parallelogram"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n15">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="52.0" width="142.0601162719767" x="1088.5370809936471" y="490.9227263183567"/>
+ <y:Fill color="#BCDD5F" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="48.103515625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="110.716796875" x="15.671659698488384" xml:space="preserve" y="1.9482421875">Non dedicated,
+Physically protected
+HW<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="parallelogram"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n16">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="71.230075781258" width="157.46968750000036" x="1356.3271972656235" y="481.3076884277277"/>
+ <y:Fill color="#DDD55F" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="48.103515625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="131.39453125" x="13.03757812500021" xml:space="preserve" y="11.563280078128969">Non dedicated,
+Not physically protected
+HW<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="parallelogram"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n17">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="12.496800000000093" width="167.67999999999955" x="999.834394531249" y="563.9227263183567"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#FF0000" raised="false" type="dashed" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.0078125" x="5.751194618473619" xml:space="preserve" y="-3.1021859374999394">TB4<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="-0.5" labelRatioY="0.0" nodeRatioX="-0.46570136797188844" nodeRatioY="1.1102230246251565E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n18">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="355.14698105468574" width="12.179999999999325" x="1318.632197265624" y="307.6918526367132"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#FF0000" raised="false" type="dashed" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.0078125" x="-6.913906250000309" xml:space="preserve" y="168.22290458984287">TB5<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="2.3314683517128287E-15" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n19" yfiles.foldertype="group">
+ <data key="d4" xml:space="preserve"/>
+ <data key="d6">
+ <y:ProxyAutoBoundsNode>
+ <y:Realizers active="0">
+ <y:GroupNode>
+ <y:Geometry height="188.8417925826776" width="475.4228202048764" x="747.7325835416852" y="-14.110811983915937"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="475.4228202048764" x="0.0" xml:space="preserve" y="0.0">Color code</y:NodeLabel>
+ <y:Shape type="roundrectangle"/>
+ <y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
+ <y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
+ <y:BorderInsets bottom="1" bottomF="0.8802461538460875" left="0" leftF="0.0" right="14" rightF="13.896470965118851" top="0" topF="0.0"/>
+ </y:GroupNode>
+ <y:GroupNode>
+ <y:Geometry height="50.0" width="50.0" x="120.0" y="60.0"/>
+ <y:Fill color="#F2F0D8" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#B7B69E" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.02685546875" x="-4.513427734375" xml:space="preserve" y="0.0">Folder 1</y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ <y:DropShadow color="#D2D2D2" offsetX="4" offsetY="4"/>
+ <y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
+ <y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
+ <y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
+ </y:GroupNode>
+ </y:Realizers>
+ </y:ProxyAutoBoundsNode>
+ </data>
+ <graph edgedefault="directed" id="n19:">
+ <node id="n19::n0">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="30.0" width="200.59682538012066" x="762.8989327814432" y="23.265652859834063"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="114.736328125" x="42.93024862756033" xml:space="preserve" y="5.6494140625">Isolated components<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n19::n1">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="30.0" width="200.67999999999978" x="762.8157581615641" y="128.8507344449156"/>
+ <y:Fill color="#DDD55F" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="151.41015625" x="24.634921874999918" xml:space="preserve" y="5.6494140625">Exposed to physical access<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n19::n2">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="30.0" width="200.76317461987873" x="762.7325835416852" y="76.05819365237483"/>
+ <y:Fill color="#BCDD5F" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="106.0703125" x="47.34643105993939" xml:space="preserve" y="5.6494140625">Isolated but shared<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n19::n3">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="30.0" width="200.7631746198785" x="993.4957581615641" y="76.05819365237483"/>
+ <y:Fill color="#CCCCCC" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="162.736328125" x="19.013423247439164" xml:space="preserve" y="5.6494140625">Out-of-scope, must be trusted<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n19::n4">
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="30.0" width="200.76317461987873" x="993.495758161564" y="23.265652859834063"/>
+ <y:Fill color="#FFDD56" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="71.37109375" x="64.69604043493928" xml:space="preserve" y="5.6494140625">Non-isolated<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ </graph>
+ </node>
+ <edge id="e0" source="n6" target="n3">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="100.35106717916995" ty="90.5448068626963"/>
+ <y:LineStyle color="#000000" type="dotted" width="2.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="33.34375" x="-73.15855895996197" xml:space="preserve" y="23.397088022583603">DF12<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e1" source="n4" target="n3">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="87.3301092996351" ty="-53.368876149144754">
+ <y:Point x="789.0" y="443.36824352897344"/>
+ <y:Point x="670.0" y="453.09318525391524"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="-93.31397923028646" xml:space="preserve" y="13.511950700802515">DF2<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="24.848250729860908" distanceToCenter="true" position="center" ratio="0.36841189565104326" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e2" source="n5" target="n4">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="-13.334968261719723" xml:space="preserve" y="-127.81154663086295">DF5<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e3" source="n4" target="n13">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="13.663771972656832" xml:space="preserve" y="-9.35058217772638">DF8<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e4" source="n13" target="n14">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="33.34375" x="25.889809570311172" xml:space="preserve" y="-9.35058217772638">DF11<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e5" source="n4" target="n11">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e6" source="n5" target="n15">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="21.485103988645278" xml:space="preserve" y="-53.840221362313514">DF7<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e7" source="n4" target="n15">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="22.99748608880236" xml:space="preserve" y="38.620743090823">DF6<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="0.4445858052130681" distanceToCenter="true" position="left" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e8" source="n4" target="n16">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="109.69154907226448" xml:space="preserve" y="37.82232548473888">DF9<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e9" source="n5" target="n16">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="33.34375" x="103.00539184570198" xml:space="preserve" y="-53.07938396899635">DF10<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e10" source="n4" target="n12">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="923.0" y="478.0"/>
+ <y:Point x="754.0338550742626" y="478.0"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="-69.70529382688164" xml:space="preserve" y="39.334672900394594">DF4<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="23.364876657804036" distanceToCenter="false" position="center" ratio="0.49999999999999944" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e11" source="n4" target="n3">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="100.34788915745409" ty="-131.82261894531433"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="-228.85351440429793" xml:space="preserve" y="-9.35058217772638">DF1<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e12" source="n4" target="n5">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="770.0980849792" y="503.8026947265723"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="26.669921875" x="-107.35476828593619" xml:space="preserve" y="36.06179093568505">DF3<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.32879346603393395" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e13" source="n10" target="n4">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="-46.75109261252976" sy="-9.459533667717096" tx="0.0" ty="0.0">
+ <y:Point x="691.103216783217" y="467.8363636363635"/>
+ <y:Point x="817.5274592074595" y="456.72214452214445"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="standard" target="standard"/>
+ <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="33.34375" x="160.4999963748819" xml:space="preserve" y="-191.48229906486733">DF13<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="0.5921559499140859" distanceToCenter="true" position="left" ratio="0.12442805389270134" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ </graph>
+ <data key="d7">
+ <y:Resources/>
+ </data>
+</graphml>
diff --git a/docs/security/generic-data-flow.svg b/docs/security/generic-data-flow.svg
new file mode 100644
index 000000000..6e6c528a0
--- /dev/null
+++ b/docs/security/generic-data-flow.svg
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill-opacity="1" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1105" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" height="803" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto">
+ <!--Generated by ySVG 2.5-->
+ <defs id="genericDefs"/>
+ <g>
+ <defs id="defs1">
+ <clipPath clipPathUnits="userSpaceOnUse" id="clipPath1">
+ <path d="M0 0 L1105 0 L1105 803 L0 803 L0 0 Z"/>
+ </clipPath>
+ <clipPath clipPathUnits="userSpaceOnUse" id="clipPath2">
+ <path d="M332 -58 L1524 -58 L1524 808.2226 L332 808.2226 L332 -58 Z"/>
+ </clipPath>
+ </defs>
+ <g stroke-linecap="butt" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" fill="red" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke-dasharray="6,2" stroke="red" stroke-miterlimit="1.45">
+ <rect fill="none" x="999.8344" width="167.68" height="12.4968" y="457.4259" clip-path="url(#clipPath2)"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <text x="1005.8344" xml:space="preserve" y="468.3882" clip-path="url(#clipPath2)" stroke="none">TB3</text>
+ </g>
+ <g stroke-linecap="butt" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" fill="red" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke-dasharray="6,2" stroke="red" stroke-miterlimit="1.45">
+ <rect fill="none" x="583.5935" width="12.18" height="564.01" y="200.6221" clip-path="url(#clipPath2)"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <text x="578.6796" xml:space="preserve" y="233.5969" clip-path="url(#clipPath2)" stroke="none">TB1</text>
+ </g>
+ <g stroke-linecap="butt" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" fill="red" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke-dasharray="6,2" stroke="red" stroke-miterlimit="1.45">
+ <rect fill="none" x="857.1073" width="12.18" height="315.4092" y="398.4487" clip-path="url(#clipPath2)"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <text x="852.1934" xml:space="preserve" y="578.4553" clip-path="url(#clipPath2)" stroke="none">TB2</text>
+ </g>
+ <g stroke-linecap="round" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-dashoffset="2" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke-dasharray="0,4" stroke-miterlimit="1.45">
+ <rect fill="none" x="342.9416" width="200.68" height="342.987" y="329.3092" clip-path="url(#clipPath2)"/>
+ </g>
+ <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,255,204)">
+ <rect x="974.6587" width="149.1406" height="52" y="342.9801" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="974.6587" width="149.1406" height="52" y="342.9801" clip-path="url(#clipPath2)"/>
+ <text x="1002.2104" xml:space="preserve" y="373.6939" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Trusted Service 1</text>
+ </g>
+ <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,255,204)">
+ <rect x="974.6587" width="149.1406" height="52" y="631.902" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="974.6587" width="149.1406" height="52" y="631.902" clip-path="url(#clipPath2)"/>
+ <text x="1002.2104" xml:space="preserve" y="662.6158" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Trusted Service 2</text>
+ </g>
+ <g fill="rgb(204,204,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,204,204)">
+ <rect x="656.595" width="149.1406" height="95.371" y="434.9416" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="656.595" width="149.1406" height="95.371" y="434.9416" clip-path="url(#clipPath2)"/>
+ <text x="718.1633" xml:space="preserve" y="487.341" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">SPM</text>
+ </g>
+ <g fill="rgb(255,221,86)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(255,221,86)">
+ <rect x="367.4203" width="149.1406" height="52" y="346.1595" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="367.4203" width="149.1406" height="52" y="346.1595" clip-path="url(#clipPath2)"/>
+ <text x="407.6371" xml:space="preserve" y="376.8734" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">u-boot/EDK2</text>
+ </g>
+ <g fill="rgb(255,221,86)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(255,221,86)">
+ <rect x="367.4203" width="149.1406" height="52" y="415.1892" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="367.4203" width="149.1406" height="52" y="415.1892" clip-path="url(#clipPath2)"/>
+ <text x="394.9721" xml:space="preserve" y="445.9031" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Operating system</text>
+ </g>
+ <g fill="rgb(255,221,86)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(255,221,86)">
+ <rect x="367.4203" width="149.1406" height="52" y="496.9892" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="367.4203" width="149.1406" height="52" y="496.9892" clip-path="url(#clipPath2)"/>
+ <text x="380.9594" xml:space="preserve" y="527.7031" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">User-space application</text>
+ </g>
+ <g fill="rgb(204,204,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,204,204)">
+ <rect x="625.7735" width="149.1406" height="52" y="631.902" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="625.7735" width="149.1406" height="52" y="631.902" clip-path="url(#clipPath2)"/>
+ <text x="662.671" xml:space="preserve" y="662.6158" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">FF-A Manifest</text>
+ </g>
+ <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,255,204)">
+ <path d="M993.5156 245.6201 L1105.9108 245.6201 L1093.4224 297.6201 L981.0273 297.6201 Z" fill-rule="evenodd" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <path fill="none" d="M993.5156 245.6201 L1105.9108 245.6201 L1093.4224 297.6201 L981.0273 297.6201 Z" fill-rule="evenodd" clip-path="url(#clipPath2)"/>
+ <text x="1014.7844" xml:space="preserve" y="261.6328" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Dedicated,</text>
+ <text x="990.1106" xml:space="preserve" y="276.334" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Physically protected</text>
+ <text x="1033.4729" xml:space="preserve" y="291.0351" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">HW</text>
+ </g>
+ <g fill="rgb(204,204,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,204,204)">
+ <rect x="691.3269" width="149.1406" height="52" y="554.354" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="691.3269" width="149.1406" height="52" y="554.354" clip-path="url(#clipPath2)"/>
+ <text x="738.2117" xml:space="preserve" y="585.0678" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Debug-log</text>
+ </g>
+ <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,255,204)">
+ <path d="M1188.1769 356.8001 L1281.5972 356.8001 L1271.2172 381.1601 L1177.7968 381.1601 Z" fill-rule="evenodd" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <path fill="none" d="M1188.1769 356.8001 L1281.5972 356.8001 L1271.2172 381.1601 L1177.7968 381.1601 Z" fill-rule="evenodd" clip-path="url(#clipPath2)"/>
+ <text x="1187.6794" xml:space="preserve" y="373.6939" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Peripheral IFC2</text>
+ </g>
+ <g fill="rgb(221,213,95)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(221,213,95)">
+ <path d="M1372.0742 333.3651 L1513.7969 333.3651 L1498.0499 404.5951 L1356.3271 404.5951 Z" fill-rule="evenodd" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <path fill="none" d="M1372.0742 333.3651 L1513.7969 333.3651 L1498.0499 404.5951 L1356.3271 404.5951 Z" fill-rule="evenodd" clip-path="url(#clipPath2)"/>
+ <text x="1406.3774" xml:space="preserve" y="358.9928" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Dedicated,</text>
+ <text x="1371.3647" xml:space="preserve" y="373.6939" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Not physically protected</text>
+ <text x="1425.0659" xml:space="preserve" y="388.3951" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">HW</text>
+ </g>
+ <g fill="rgb(188,221,95)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(188,221,95)">
+ <path d="M1102.743 490.9227 L1230.5972 490.9227 L1216.3912 542.9227 L1088.5371 542.9227 Z" fill-rule="evenodd" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <path fill="none" d="M1102.743 490.9227 L1230.5972 490.9227 L1216.3912 542.9227 L1088.5371 542.9227 Z" fill-rule="evenodd" clip-path="url(#clipPath2)"/>
+ <text x="1119.2048" xml:space="preserve" y="506.9354" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Non dedicated,</text>
+ <text x="1106.2087" xml:space="preserve" y="521.6366" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Physically protected</text>
+ <text x="1149.571" xml:space="preserve" y="536.3378" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">HW</text>
+ </g>
+ <g fill="rgb(221,213,95)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(221,213,95)">
+ <path d="M1372.0742 481.3077 L1513.7969 481.3077 L1498.0499 552.5378 L1356.3271 552.5378 Z" fill-rule="evenodd" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <path fill="none" d="M1372.0742 481.3077 L1513.7969 481.3077 L1498.0499 552.5378 L1356.3271 552.5378 Z" fill-rule="evenodd" clip-path="url(#clipPath2)"/>
+ <text x="1394.6997" xml:space="preserve" y="506.9354" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Non dedicated,</text>
+ <text x="1371.3647" xml:space="preserve" y="521.6366" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Not physically protected</text>
+ <text x="1425.0659" xml:space="preserve" y="536.3378" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">HW</text>
+ <rect x="999.8344" y="563.9227" clip-path="url(#clipPath2)" fill="none" width="167.68" stroke-dasharray="6,2" height="12.4968" stroke="red"/>
+ <text x="1007.5856" xml:space="preserve" y="574.885" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">TB4</text>
+ <rect x="1318.6322" y="307.6919" clip-path="url(#clipPath2)" fill="none" width="12.18" stroke-dasharray="6,2" height="355.147" stroke="red"/>
+ <text x="1313.7183" xml:space="preserve" y="489.9792" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">TB5</text>
+ <path fill="none" d="M966.9668 392.4953 L789 443.3683 L670 453.0932 L551.6387 448.2875" clip-path="url(#clipPath2)"/>
+ <path d="M974.6587 390.2965 L961.7466 388.7872 L966.0053 392.7701 L964.4951 398.4021 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M543.6453 447.963 L555.4326 453.4457 L552.6379 448.3281 L555.8383 443.4539 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="881.3447" y="403.8084" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="883.3447" xml:space="preserve" y="417.8729" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">DF2</text>
+ <path fill="none" d="M966.6587 368.9801 L551.6295 368.9801" clip-path="url(#clipPath2)"/>
+ <path d="M974.6587 368.9801 L962.6587 363.9801 L965.6587 368.9801 L962.6587 373.9801 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M543.6295 368.9801 L555.6295 373.9801 L552.6295 368.9801 L555.6295 363.9801 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="745.8052" y="359.6295" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="747.8052" xml:space="preserve" y="373.6939" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">DF1</text>
+ <path fill="none" d="M988.196 398.4595 L770.0981 503.8027 L995.1298 628.0355" clip-path="url(#clipPath2)"/>
+ <path d="M995.3997 394.9801 L982.4195 395.697 L987.2955 398.8945 L986.7689 404.7016 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1002.1334 631.902 L994.0445 621.725 L994.2543 627.5522 L989.2114 630.4796 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="888.045" y="431.0419" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="890.0449" xml:space="preserve" y="445.1063" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">DF3</text>
+ <path fill="none" d="M1049.229 623.902 L1049.229 402.9801" clip-path="url(#clipPath2)"/>
+ <path d="M1049.229 631.902 L1054.229 619.902 L1049.229 622.902 L1044.229 619.902 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1049.229 394.9801 L1044.229 406.9801 L1049.229 403.9801 L1054.229 406.9801 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="1035.894" y="504.0904" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="1037.894" xml:space="preserve" y="518.1549" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">DF5</text>
+ </g>
+ <g stroke-linecap="round" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-dashoffset="2" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke-dasharray="0,8" stroke-width="2" stroke-miterlimit="1.45">
+ <path fill="none" d="M648.8088 530.3726 L551.4188 586.8336" clip-path="url(#clipPath2)"/>
+ <path d="M656.595 525.8586 L642.0945 527.7632 L647.8356 530.9368 L647.737 537.4959 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M543.6326 591.3475 L558.1331 589.443 L552.3921 586.2693 L552.4907 579.7103 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="583.4364" y="549.2557" clip-path="url(#clipPath2)" fill="white" width="33.3438" height="18.7012" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <text x="585.4364" xml:space="preserve" y="563.3201" clip-path="url(#clipPath2)" stroke="none">DF12</text>
+ <path fill="none" d="M658.6537 624.0746 L691.1032 467.8364 L817.5275 456.7221 L973.0889 397.8132" clip-path="url(#clipPath2)"/>
+ <path d="M657.0269 631.9074 L664.3627 621.1749 L658.8571 623.0955 L654.5716 619.1414 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M980.5704 394.9801 L967.5775 394.5538 L972.1537 398.1674 L971.1188 403.9058 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="817.5269" y="440.4252" clip-path="url(#clipPath2)" fill="white" width="33.3438" height="18.7012" stroke="none"/>
+ <text x="819.5269" xml:space="preserve" y="454.4896" clip-path="url(#clipPath2)" stroke="none">DF13</text>
+ <path fill="none" d="M1047.2183 334.994 L1045.4813 305.6344" clip-path="url(#clipPath2)"/>
+ <path d="M1047.6908 342.9801 L1051.9733 330.7057 L1047.1592 333.9958 L1041.9907 331.2964 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1045.0089 297.6483 L1040.7262 309.9227 L1045.5404 306.6326 L1050.7089 309.3322 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path fill="none" d="M1013.0703 400.2091 L923 478 L754.0339 478 L761.9626 546.4072" clip-path="url(#clipPath2)"/>
+ <path d="M1019.1248 394.9801 L1006.7749 399.0396 L1012.3135 400.8628 L1013.3112 406.6077 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M762.8837 554.3539 L766.4688 541.8581 L761.8475 545.4138 L756.5353 543.0094 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="949.4195" y="434.3147" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="951.4195" xml:space="preserve" y="448.3792" clip-path="url(#clipPath2)" stroke="none">DF4</text>
+ <path fill="none" d="M1131.7993 368.9801 L1174.979 368.9801" clip-path="url(#clipPath2)"/>
+ <path d="M1123.7993 368.9801 L1135.7993 373.9801 L1132.7993 368.9801 L1135.7993 363.9801 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1182.979 368.9801 L1170.979 363.9801 L1173.979 368.9801 L1170.979 373.9801 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="1137.4631" y="359.6295" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="1139.4631" xml:space="preserve" y="373.6939" clip-path="url(#clipPath2)" stroke="none">DF8</text>
+ <path fill="none" d="M1284.4005 368.9801 L1356.2144 368.9801" clip-path="url(#clipPath2)"/>
+ <path d="M1276.4005 368.9801 L1288.4005 373.9801 L1285.4005 368.9801 L1288.4005 363.9801 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1364.2144 368.9801 L1352.2144 363.9801 L1355.2144 368.9801 L1352.2144 373.9801 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="1302.2903" y="359.6295" clip-path="url(#clipPath2)" fill="white" width="33.3438" height="18.7012" stroke="none"/>
+ <text x="1304.2903" xml:space="preserve" y="373.6939" clip-path="url(#clipPath2)" stroke="none">DF11</text>
+ <path fill="none" d="M1074.5087 625.6021 L1134.2703 549.2445" clip-path="url(#clipPath2)"/>
+ <path d="M1069.578 631.902 L1080.9114 625.5338 L1075.125 624.8146 L1073.0365 619.3705 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1139.2009 542.9446 L1127.8676 549.3128 L1133.6539 550.032 L1135.7423 555.4761 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="1091.0631" y="578.0618" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="1093.0631" xml:space="preserve" y="592.1262" clip-path="url(#clipPath2)" stroke="none">DF7</text>
+ <path fill="none" d="M1073.4031 401.3929 L1135.4004 484.5197" clip-path="url(#clipPath2)"/>
+ <path d="M1068.6202 394.9801 L1071.7865 407.5886 L1074.001 402.1945 L1079.8025 401.61 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1140.1832 490.9325 L1137.017 478.324 L1134.8025 483.718 L1129.001 484.3025 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="1091.6177" y="433.6008" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="1093.6177" xml:space="preserve" y="447.6653" clip-path="url(#clipPath2)" stroke="none">DF6</text>
+ <path fill="none" d="M1124.5065 397.8442 L1362.2559 489.0061" clip-path="url(#clipPath2)"/>
+ <path d="M1117.0367 394.9801 L1126.4512 403.9449 L1125.4402 398.2022 L1130.0314 394.6078 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1369.7256 491.8703 L1360.3112 482.9055 L1361.3221 488.6481 L1356.731 492.2426 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="1226.7283" y="432.8024" clip-path="url(#clipPath2)" fill="white" width="26.6699" height="18.7012" stroke="none"/>
+ <text x="1228.7283" xml:space="preserve" y="446.8669" clip-path="url(#clipPath2)" stroke="none">DF9</text>
+ <path fill="none" d="M1127.9001 629.1564 L1350.4539 547.8376" clip-path="url(#clipPath2)"/>
+ <path d="M1120.386 631.902 L1133.3732 632.4799 L1128.8394 628.8132 L1129.9412 623.0873 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <path d="M1357.968 545.0921 L1344.9808 544.5142 L1349.5146 548.1808 L1348.4128 553.9068 Z" clip-path="url(#clipPath2)" stroke="none"/>
+ <rect x="1223.3914" y="578.8226" clip-path="url(#clipPath2)" fill="white" width="33.3438" height="18.7012" stroke="none"/>
+ <text x="1225.3914" xml:space="preserve" y="592.887" clip-path="url(#clipPath2)" stroke="none">DF10</text>
+ </g>
+ <g fill="rgb(235,235,235)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(235,235,235)">
+ <rect x="747.7326" width="475.4228" height="22.3765" y="-14.1108" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g font-size="15px" stroke-linecap="butt" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" text-rendering="geometricPrecision" font-family="sans-serif" shape-rendering="geometricPrecision" stroke-miterlimit="1.45">
+ <text x="949.1744" xml:space="preserve" y="2.9698" clip-path="url(#clipPath2)" stroke="none">Color code</text>
+ <rect x="747.7326" y="-14.1108" clip-path="url(#clipPath2)" fill="none" width="475.4228" stroke-dasharray="6,2" rx="4" ry="4" height="188.8418"/>
+ </g>
+ <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,255,204)">
+ <rect x="762.8989" width="200.5968" height="30" y="23.2657" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="762.8989" width="200.5968" height="30" y="23.2657" clip-path="url(#clipPath2)"/>
+ <text x="807.8292" xml:space="preserve" y="42.9795" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Isolated components</text>
+ </g>
+ <g fill="rgb(221,213,95)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(221,213,95)">
+ <rect x="762.8158" width="200.68" height="30" y="128.8507" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="762.8158" width="200.68" height="30" y="128.8507" clip-path="url(#clipPath2)"/>
+ <text x="789.4507" xml:space="preserve" y="148.5646" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Exposed to physical access</text>
+ </g>
+ <g fill="rgb(188,221,95)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(188,221,95)">
+ <rect x="762.7326" width="200.7632" height="30" y="76.0582" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="762.7326" width="200.7632" height="30" y="76.0582" clip-path="url(#clipPath2)"/>
+ <text x="812.079" xml:space="preserve" y="95.7721" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Isolated but shared</text>
+ </g>
+ <g fill="rgb(204,204,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(204,204,204)">
+ <rect x="993.4958" width="200.7632" height="30" y="76.0582" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="993.4958" width="200.7632" height="30" y="76.0582" clip-path="url(#clipPath2)"/>
+ <text x="1014.5092" xml:space="preserve" y="95.7721" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Out-of-scope, must be trusted</text>
+ </g>
+ <g fill="rgb(255,221,86)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke="rgb(255,221,86)">
+ <rect x="993.4958" width="200.7632" height="30" y="23.2657" clip-path="url(#clipPath2)" stroke="none"/>
+ </g>
+ <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(0.927,0,0,0.927,-307.7685,53.7668)" stroke-linecap="butt">
+ <rect fill="none" x="993.4958" width="200.7632" height="30" y="23.2657" clip-path="url(#clipPath2)"/>
+ <text x="1060.1918" xml:space="preserve" y="42.9795" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none">Non-isolated</text>
+ </g>
+ </g>
+</svg>
diff --git a/docs/security/index.rst b/docs/security/index.rst
index ac271be6f..513c3fd15 100644
--- a/docs/security/index.rst
+++ b/docs/security/index.rst
@@ -6,14 +6,15 @@ Security Model
:caption: Contents:
self
+ threat-model
-TODO:
-SDL
-Threat Modell
-etc..
+The security model of Trusted Services build on the `Platform Security Model`_ v1.1 beta. For a concept level overview
+please refer to this document.
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+.. _`Platform Security Model`: https://developer.arm.com/documentation/den0128/1-1/?lang=en
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/security/threat-model.rst b/docs/security/threat-model.rst
new file mode 100644
index 000000000..3bd9dd010
--- /dev/null
+++ b/docs/security/threat-model.rst
@@ -0,0 +1,439 @@
+Generic Threat Model
+====================
+
+Threat modeling is a process to identify security requirements, pinpoint security threats and potential vulnerabilities,
+quantify threat and vulnerability criticality and prioritize remediation methods.
+
+In the next sections you can find the output of this process the for a generic, use-case and service independent
+assessment.
+
+Target evaluation
+-----------------
+
+In this threat model, the target of evaluation is the S-EL0 SPs part of the PSA RoT hosting a "generalized" trusted
+service.
+
+This evaluation is based on the following assumptions:
+
+ * The implementation is based on the |FF-A| standard.
+ * Trusted boot is enabled. This means an attacker can’t boot arbitrary images that are not approved by platform
+ providers.
+ * Each trusted service is running in an S-EL0 secure partition. Access to memory and hardware is controlled by the
+ SPM based on the FF-A manifest or FF-A framework messages.
+ * Components running at higher privilege levels than S-EL0 are to be inherently trusted. (I.e. the SPM).
+
+Data flow diagram
+-----------------
+
+The data flow diagram visualizes the connection between components and where the data flow crosses security boundaries.
+
+.. image:: ./generic-data-flow.svg
+ :target: Attachments_
+
+.. table:: List of data flows
+
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | Data flow | Description | In scope |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF1 | Trusted Service interacts with NWd client directly. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF2 | Trusted Service interacts with NWd client through SPM. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF3 | Trusted Services interact through SPM. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF4 | Trusted Service logs debug information. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF5 | Trusted Services interact directly. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF6, DF7 | Trusted Services interacts with shared hardware. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF8 | Trusted Service interacts with dedicated peripheral interface. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF9, DF10 | Trusted Service interacts with shared, external hardware. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF11 | Trusted Service interacts with dedicated, external hardware. | Yes |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF12 | NWd interacts with more privileged software. | No |
+ +-----------+---------------------------------------------------------------------------------+----------+
+ | DF13 | FF-A manifest and other data is handed over to a Trussed Service | No |
+ +-----------+---------------------------------------------------------------------------------+----------+
+
+Trust boundaries
+----------------
+
+.. list-table:: List of trust boundaries
+
+ * - Trust boundary
+ - Description
+ * - TB1
+ - Trust boundary between TEE and normal world.
+ * - TB2
+ - Trust boundary between higher privilege level SW and Trusted Services.
+ * - TB3, TB4
+ - Trust boundary between trusted services.
+ * - TB5
+ - Trust boundary to physically accessible external hardware.
+
+Assets
+------
+
+The above dataflow identifies the following generalized assets.
+
+.. table::
+
+ +----------------------+----------------------------------------------------------------------------------+
+ | Asset | Description |
+ +----------------------+----------------------------------------------------------------------------------+
+ | ``availability`` | Availability of a trusted service to clients. |
+ +----------------------+----------------------------------------------------------------------------------+
+ | ``code execution`` | Code or code flow of a trusted service. |
+ +----------------------+----------------------------------------------------------------------------------+
+ | ``sensitive data`` | Data that an attacker must not tamper with. These include device identity key, |
+ | | Initial Attestation Key, Protected Storage Key, UEFI variables, tpm-event log, |
+ | | etc... |
+ +----------------------+----------------------------------------------------------------------------------+
+ |``sensitive hardware``| Hardware that an attacker must not be tamper with. Examples are control interface|
+ | | of storage medium, true random number generator, crypto accelerator. |
+ +----------------------+----------------------------------------------------------------------------------+
+
+Attackers and threat agents
+---------------------------
+
+This section identifies the generalized stakeholders interacting with secure services.
+
+.. list-table::
+ :widths: 20,70,10
+
+ * - Attacker/Threat agent
+ - Description
+ - In scope
+ * - ``NSClient``
+ - Client executing in the normal world.
+ - Yes
+ * - ``SClient``
+ - Client running in SWd.
+ - Yes
+ * - ``HPComponent``
+ - Components running at higher privilege level than the trusted service.
+ - No
+ * - ``AppDebug``
+ - Physical attacker using debug signals to access resources.
+ - Yes
+ * - ``PhysAcc``
+ - Physical attacker having access to the external device communication bus and to the external flash communication
+ bus using common hardware.
+ - Yes
+ * - ``AdvPhysAcc``
+ - Attackers who are able to use specialist hardware for attacks that require irreversible changes to the target
+ system (e.g., "rewiring" a chip using a Focused IonBeam FIB workstation).
+ - No
+
+
+
+Threat Priority
+---------------
+
+Threat priority calculation is based on `Common Vulnerability Scoring System`_ (CVSS) Version 3.1. The threat priority
+is represented by the `Severity Rating Scale`_ calculated from the CVSS score of each threat. The CVSS score is
+calculated using the `Vulnerability Calculator`_.
+
+For each threat the priority and a link to CVSS calculator capturing the calculator settings will be listed.
+
+Threat Types
+------------
+
+In this threat model we categorize threats using the `STRIDE threat analysis technique`_. In this technique a threat is
+categorized as one or more of these types: ``Spoofing``, ``Tampering``, ``Repudiation``, ``Information disclosure``,
+``Denial of service`` or ``Elevation of privilege``.
+
+.. list-table::
+ :widths: 15,80
+
+ * - **ID**
+ - 1
+ * - Description
+ - Information leak via debug logs.
+
+ During development it is common practice to help understanding code execution by emitting
+ debug logs.
+ * - Data flow
+ - DF4
+ * - Asset(s)
+ - ``Sensitive Data``
+ * - Threat Agent/Attacker
+ - ``AppDebug``
+ * - Threat type
+ - ``Information disclosure``
+ * - Impact
+ - Sensitive information may get to unauthorized people. Information can potentially help
+ compromising the target or other systems.
+ * - Scoring/CVSS
+ - Medium, 4.6 `CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N>`_
+ * - Mitigation
+ - Log messages are put to "verbosity categories". Release builds limit printed log messages
+ to "error" category.
+ * - Mitigation in place
+ - yes
+
+.. list-table::
+ :widths: 15,80
+
+ * - **ID**
+ - 2
+ * - Description
+ - An attacker can tamper with sensitive data and execute arbitrary code through hardware-assisted
+ debug interface.
+ * - Data flow
+ - N/A.
+ * - Asset(s)
+ - ``Sensitive Data``, ``Code Execution``, ``Sensitive Hardware``
+ * - Threat Agent/Attacker
+ - ``AppDebug``
+ * - Threat type
+ - ``Information disclosure``, ``Tampering``
+ * - Impact
+ - Sensitive information may get to unauthorized people. Information can potentially help
+ compromising the target or other systems.
+
+ An attacker may modify sensitive data and alter device behavior and thus compromise the
+ target or other systems.
+ * - Scoring/CVSS
+ - Medium, 6.8 `CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H>`_
+ * - Mitigation
+ - Hardware platform specific means to disable or limit access to debug functionality.
+ * - Mitigation in place
+ - yes
+
+.. list-table::
+ :widths: 15,80
+
+ * - **ID**
+ - 3
+ * - Description
+ - An attacker can perform a denial-of-service attack by using a broken service call that
+ causes the service to enter an unknown state.
+
+ Secure and non-secure clients access a trusted service through FF-A calls. Malicious code
+ can attempt to place the service into an inconsistent state by calling unimplemented
+ calls or by passing invalid arguments.
+ * - Data flow
+ - DF1, DF2, DF3, DF5
+ * - Asset(s)
+ - ``Availability``
+ * - Threat Agent/Attacker
+ - ``NSclient``, ``SClient``
+ * - Threat type
+ - ``Denial of service``
+ * - Impact
+ - The service or the whole system may temporarily or permanently enter an unusable state.
+ * - Scoring/CVSS
+ - Medium, 6.8 `CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H>`_
+ * - Mitigation
+ - The service must validate all inputs before usage. Input validation shall be checked during
+ code review and by testing.
+ * - Mitigation in place
+ - yes
+
+.. list-table::
+ :widths: 15,80
+
+ * - **ID**
+ - 4
+ * - Description
+ - Memory corruption due to memory overflows and lack of boundary checking when accessing
+ resources.
+
+ Allows an attacker to execute arbitrary code, modify memory content to change
+ program flow.
+ * - Data flow
+ - DF1, DF2, DF3, DF5
+ * - Asset(s)
+ - ``Code execution``, ``Sensitive Data``, ``Denial of service``
+ * - Threat Agent/Attacker
+ - ``SClient``, ``NSClient``, ``HSComponent``
+ * - Threat type
+ - ``Tampering``, ``Information disclosure``, ``Elevation of privilege``, ``Denial of service``
+ * - Impact
+ - The service or the whole system may temporarily or permanently enter an unusable state.
+
+ Malicious code might be executed in the context of the compromised service.
+ Leakage of sensitive data.
+ * - Scoring/CVSS
+ - High, 8.4 `CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H>`_
+ * - Mitigation
+ - The service must validate boundaries and sanity check incoming data. Validation shall be
+ checked during code reviews and by testing.
+ * - Mitigation in place
+ - yes
+
+.. list-table::
+ :widths: 15,80
+
+ * - **ID**
+ - 5
+ * - Description
+ - External devices connected to the system storing sensitive data. An attacker could eavesdrop external signals.
+ * - Data flow
+ - DF9, DF10, DF11
+ * - Asset(s)
+ - ``Sensitive Data``
+ * - Threat agent/Attacker
+ - ``PhysAcc``
+ * - Threat type
+ - ``Information disclosure``
+ * - Impact
+ - An attacker may get access to sensitive data, could tamper with sensitive data, or could attack the service
+ using the external device by injecting malicious data, which could lead to malfunction or execution of malicious
+ code.
+ * - Scoring/CVSS
+ - Medium, 5.9 `CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H>`_
+ * - Mitigation
+ - When designing the use case, storage services must be assessed to understand which protection type they can
+ implement (integrity, authenticity, confidentiality, rollback-protection). Sensitive data must be categorized
+ and mapped to the storage service which can provide the needed protection.
+
+ For example integrity can be safeguarded by using checksums. Authenticity by using digital signatures.
+ Confidentiality by using encryption. Rollback protection by using nonce values.
+ * - Mitigation in place
+ - yes
+
+.. list-table::
+ :widths: 15,80
+
+ * - **ID**
+ - 6
+ * - Description
+ - State of external devices connected to the system might be modified by an attacker.
+
+ This includes modifying signals, replacing the device, or modifying device content.
+ * - Data flow
+ - DF9, DF10, DF11
+ * - Asset(s)
+ - ``Sensitive Data``, ``Denial of service``, ``Code execution``
+ * - Threat agent/Attacker
+ - ``PhysAcc``
+ * - Threat type
+ - ``Tampering``, ``Denial of service``, ``Code execution``
+ * - Impact
+ - An attacker could tamper with sensitive data, or could attack the system by injecting malicious data, which
+ could lead to malfunction, execution of malicious code, or using old state with known vulnerability.
+ * - Scoring/CVSS
+ - High, 7.3 `CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H>`_
+ * - Mitigation
+ - When designing the use case, storage services must be assessed to understand which protection type they can
+ implement (integrity, authenticity, confidentiality, rollback-protection). Sensitive data must be categorized
+ and mapped to the storage service which can provide the needed protection.
+
+ For example integrity can be safeguarded by using checksums. Authenticity by using digital signatures.
+ Confidentiality by using encryption. Rollback protection by using hardware backed nonce values.
+ * - Mitigation in place
+ - yes
+
+
+.. list-table::
+ :widths: 15,80
+
+ * - ID
+ - 7
+ * - Description
+ - Invalid or conflicting access to shared hardware.
+
+ * - Data flow
+ - DF6, DF7, DF9, DF10
+ * - Asset(s)
+ - ``Sensitive Data``, ``Denial of service``, ``Code execution``
+ * - Threat Agent/Attacker
+ - ``SClient``, ``NSClient``, ``HPComponent``
+ * - Threat type
+ - ``Tampering``, ``Information disclosure``, ``Denial of service``, ``Code execution``
+ * - Impact
+ - A trusted service relying on shared hardware usage might get compromised or misbehaving if other stakeholders
+ affect shared hardware in unexpected way.
+
+ * - Scoring/CVSS
+ - High, 7.0 `CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:H <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:H>`_
+ * - Mitigation
+ - Access to peripherals must be limited to the smallest possible set of services. Ideally each peripheral should be
+ dedicated to a single trusted service and sharing of peripherals should be avoided is possible. If sharing can
+ not be avoided, a strict handover process shall be implemented to allow proper context switches, where hardware
+ state can be controlled.
+ * - Mitigation in place
+ - yes
+
+.. list-table::
+ :widths: 15,80
+
+ * - **ID**
+ - 8
+ * - Description
+ - Unauthenticated access to hardware.
+
+ A trusted service relying on hardware usage might get compromised or misbehaving if hardware state is
+ maliciously altered.
+ * - Data flow
+ - DF6, DF7, DF9, DF10
+ * - Asset(s)
+ - ``Sensitive Data``, ``Denial of service``, ``Code execution``
+ * - Threat Agent/Attacker
+ - ``SClient``, ``NSClient``, ``HPComponent``
+ * - Threat type
+ - ``Tampering``, ``Information disclosure``, ``Denial of service``, ``Code execution``
+ * - Impact
+ - An attacker may get access to sensitive data of might make a trusted service or the system enter an unusable
+ state by tampering with hardware peripherals.
+ * - Scoring/CVSS
+ - Medium, 6.4 `CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H>`_
+ * - Mitigation
+ - Access to peripherals must be limited to the smallest possible set of services. Ideally each peripheral should be
+ dedicated to a single trusted service, and sharing of peripherals should be avoided is possible. If sharing can
+ not be avoided, a strict handover process shall be implemented to allow proper context switches, where register
+ values can be controlled.
+ * - Mitigation in place
+ - yes
+
+
+.. list-table::
+ :widths: 15,80
+
+ * - **ID**
+ - 9
+ * - Description
+ - Unauthenticated access to sensitive data.
+ * - Data flow
+ - DF1, DF2, DF3, DF5
+ * - Asset(s)
+ - ``Sensitive Data``, ``Denial of service``
+ * - Threat Agent/Attacker
+ - ``SClient``, ``NSClient``, ``HPComponent``
+ * - Threat type
+ - ``Tampering``, ``Information disclosure``, ``Denial of service``
+ * - Impact
+ - A trusted service may manage data of multiple clients. Different clients shall not be able to access each
+ other's data unless in response to explicit request.
+ * - Scoring/CVSS
+ - Medium, 6.8 `CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N <https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N>`_
+ * - Mitigation
+ - Trusted services must implement access control based on identification data provided by higher privileged
+ components (i.e. FF-A endpoint ID).
+ * - Mitigation in place
+ - yes
+
+
+--------------
+
+.. _Attachments:
+.. Rubric:: Attachments
+
+Source file of the `Data flow diagram`_. Please use the yEd_ for editing. :download:`./generic-data-flow.graphml`
+
+--------------
+
+.. _`Common Vulnerability Scoring System`: https://www.first.org/cvss/v3.1/specification-document
+.. _`Vulnerability Calculator`: https://www.first.org/cvss/calculator/3.1
+.. _`Severity Rating Scale`: https://www.first.org/cvss/v3.1/specification-document#Qualitative-Severity-Rating-Scale
+.. _`STRIDE threat analysis technique`: https://docs.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats#stride-model
+.. _yEd: https://www.yworks.com/products/yed
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/service-descriptions/attest-service-description.rst b/docs/services/attest-service-description.rst
index 2843ede9e..2e872f295 100644
--- a/docs/developer/service-descriptions/attest-service-description.rst
+++ b/docs/services/attest-service-description.rst
@@ -1,7 +1,7 @@
-Attestation Service Description
-===============================
-Service Overview
-----------------
+Attestation Service
+===================
+Overview
+--------
The Attestation service is responsible for reporting on the security state of a device.
Because information is signed, a remote party may verify that the information is intact
and authentic. The Attestation service can be used as part of an infrastructure for
@@ -264,6 +264,6 @@ Tests included in the *env_test* SP deployment may be invoked from Linux user-sp
--------------
-*Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/services/block-storage-service-description.rst b/docs/services/block-storage-service-description.rst
new file mode 100644
index 000000000..a29f057c3
--- /dev/null
+++ b/docs/services/block-storage-service-description.rst
@@ -0,0 +1,262 @@
+Block Storage Service
+=====================
+Overview
+--------
+The Block Storage service can be used to share a block-oriented storage device
+such as a QSPI flash between a set of independent secure world clients. A block
+storage service provider presents a block level interface for accessing an
+underlying block storage device. To allow multiple higher layer filesystems to
+share the same storage device, logical block addresses are partitioned, based on
+configuration data provided by a system integrator. The partition configuration
+data may be read from a GUID Partition Table (GPT) or from the block storage SP
+manifest. The configuration data restricts access to a storage partition to a
+defined owner. Each owner is allocated a maximum number of blocks and is given
+exclusive access to its own blocks, based on the client ID of the calling client.
+
+The following diagram illustrates a firmware integration that uses a single block
+storage service provider to control access to a dedicated flash device. In this
+example StMM, OP-TEE, Update Agent and the Protected Storage SP act as clients of
+the service. Each client independently manages its own filesystem and is presented
+with its own logical partition, starting with a logical block address (LBA) of zero.
+
+.. image:: image/block-storage-example-usage.svg
+
+Project Directories
+-------------------
+Components within the Trusted Services project related to the Block Storage service
+are located under the following directories:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Directory
+ - Contains
+ * - ``components/service/block_storage``
+ - Service specific code components.
+ * - ``deployments/block-storage``
+ - Build files and deployment specific code for building alternative configurations
+ of the block storage service provider.
+ * - ``protocols/service/block_storage``
+ - Service access protocol definitions.
+
+Service Interface
+-----------------
+The Block Storage service supports a conventional set of block-level operations that
+can be adapted to different driver models by clients. The following table summarizes
+supported operations:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Operation
+ - Description
+ * - Open
+ - Open a session - take the required *UniquePartitionGUID* as a parameter. Returns
+ a handle to be used as a qualifier for other requests made by a client.
+ * - Close
+ - Close a previously opened session.
+ * - GetInfo
+ - Returns information about the partition associated with an open session. Includes
+ the block size and the total number of blocks assigned to the partition.
+ * - Read
+ - Read data from the specified block.
+ * - Write
+ - Write data to the specified block.
+ * - Erase
+ - Erase a set of one or more blocks.
+
+Protocol definitions live under: ``protocols/service/block_storage``.
+
+The service interface is realized by the block storage service provider. It delegates
+storage operations to a backend *block_store*. The *block_store* defines a common
+interface for components that realize block storage operations. Where an underlying storage
+technology does not support an explicit erase operation (e.g. RPMB), the corresponding
+concrete *block_store* should return success for a call to erase but perform no actual
+operation (if the partition is writable and the LBA falls within the limits of the
+partition).
+
+Service Provider Configuration
+------------------------------
+A platform integrator must provide a set of configuration data to configure how the block
+storage service provider presents block storage to clients. Configuration data relates to
+the following:
+
+ - **Storage partition configuration** - determines how storage is divided into separate partitions
+ - **Block device configuration** - determines how the backed storage device is configured
+
+Storage Partition Configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The block storage service allows a block storage device to be presented as a single storage
+partition or as a set of smaller storage partitions. The way that storage is presented is
+determined by configuration data prepared by a platform integrator. Each storage partition
+presented by a block storage service provider starts at LBA zero. The number of partitions
+and their size are defined by configuration data. Configuration data assigns partitions
+to owners to enable access to be controlled. If no partition configuration exists for a
+requesting client or if an attempt is made to access a block outside of the configured LBA
+range, access is denied. The set of storage partitions used for secure block storage will
+not necessarily span the entire underlying storage device. A platform integrator is free to
+limit the area used for secure block storage to allow the storage device to be used for other
+purposes e.g. as a boot source, read by the boot loader during early boot stages.
+
+Two partition configuration methods will be supported; one where partition configuration data
+is read from an SP manifest and the other where configuration is defined by a GUID Partition
+Table. Both methods may be used in combination if necessary. Initial implementations will
+use the SP manifest configuration method.
+
+Each partition configuration entry includes an attributes bitmap that conforms to the UEFI
+GPT Partition Entry attributes definition (see section 5.3 of the UEFI specification). Bits
+48-63 are reserved for GUID specific use. For partitions labelled with the Secure Block Store
+GUID, bits will be defined for:
+
+ - **Read-only** - write and erase operations are forbidden.
+
+A GPT partition entry includes the PartitionName property which normally holds a human readable
+name for the partition. For secure block store partitions, the PartitionName property will
+hold the canonical UUID string identifying the owner. An empty string is interpreted as
+'no specific owner' and any client will be granted access.
+
+Configuration via SP Manifest
+"""""""""""""""""""""""""""""
+For an SP deployment, the partition configuration may be read from a device tree blob (DTB),
+passed as an initialization parameter. Per-partition configuration data comprises the following:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Config Value
+ - Description
+ * - UniquePartitionGUID
+ - GUID that is unique for a partition entry.
+ * - StartingLBA
+ - The storage block address corresponding to LBA zero.
+ * - EndingLBA
+ - The last storage block in the contiguous range of blocks.
+ * - Attributes
+ - See UEFI specification
+ * - Owner
+ - Holds canonical UUID string for owner.
+
+The partition configuration is included as a sub-node of the block-dev node that includes
+configuration values related to the block device. The following is an example of how a block
+device and related partitions are defined within a DT based SP manifest::
+
+ block-dev {
+ compatible = "tforg,ts-block-dev"
+ disk-guid = "af9f72de-d71f-4492-b44b-a4b4d96000bf"
+
+ partitions {
+ compatible = "tforg,ts-block-partitions"
+
+ fwu-meta {
+ guid = "a6f99e90-7a75-4384-847a-29c9a86c6279"
+ start-lba = <0x00000000>
+ end-lba = <0x00000003>
+ attr = <0x00000000>
+ owner = "afb995cd-9354-4333-9ea2-bd62ccaedb22"
+ };
+
+ fip {
+ guid = "1eccc9bc-9a5f-43d0-bcd3-466fd21c9a92"
+ start-lba = <0x00000004>
+ end-lba = <0x00040003>
+ attr = <0x00000000>
+ owner = "afb995cd-9354-4333-9ea2-bd62ccaedb22"
+ };
+
+ uefi-var {
+ guid = "1022a92b-4b4a-47b4-94cb-35faf5a45dc2"
+ start-lba = <0x00040004>
+ end-lba = <0x00080003>
+ attr = <0x00000000>
+ owner = "ed32d533-99e6-4209-9cc0-2d72cdd998a7"
+ };
+ };
+ };
+
+Configuration via GUID Partition Table (GPT)
+""""""""""""""""""""""""""""""""""""""""""""
+The UEFI specification defines a standard layout for physical storage devices where storage
+partitions are described by partition entries within the GUID Partition Table. During
+initialization, the Block Storage SP will read the GPT and iterate over partition entries,
+identifying those with the secure block store partition type GUID. Each entry contains the
+following:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Offset
+ - Length
+ - contents
+ * - 0
+ - 16 bytes
+ - PartitionTypeGUID - Secure Block Store GUID
+ * - 16
+ - 16 bytes
+ - UniquePartitionGUID
+ * - 32
+ - 8 bytes
+ - Starting LBA
+ * - 40
+ - 8 bytes
+ - Ending LBA
+ * - 48
+ - 8 bytes
+ - Attributes (e.g. read-only)
+ * - 56
+ - 72 bytes
+ - PartitionName - Holds canonical UUID string for owner.
+
+Design Description
+------------------
+The block storage service provider conforms to the same model as other service providers
+within the TS project. Service requests from clients are received by a service provider
+that is responsible for parameter deserialization/serialization and service level access
+control. Block storage operations are delegated to a backend *block_store* that provides
+block-level storage in some way. There is much flexibility to realize the backend block-level
+storage in different ways, allowing platform integrators to use alternative *block_store*
+realizations to provide storage solutions that meet specific product requirements.
+
+The following class diagram illustrates the block storage service provider model:
+
+.. uml:: uml/BlockStorageProvider.puml
+
+Block Store
+^^^^^^^^^^^
+The *block_store* component defines a virtual interface for block IO operations. Alternative
+concrete *block_store* implementations are supported. Some *block_store* components are stackable
+over other *block_store* components to add features such as store partitioning or block
+authentication. Separation of functionality into stackable *block_store* components gives
+platform integrators the flexibility to create alternative storage solutions with different
+security/cost tradeoffs. The base *block_store* interface is defined in::
+
+ components/service/block_storage/block_store/block_store.h
+
+Components that implement the *block_store* interface are located in subdirectories beneath
+``components/service/block_storage/block_store``. A *block_device* is class of *block_store*
+that actually provides block-level storage. In a stack of *block_store* components, a
+*block_device* will always live at the bottom. The following layer diagram illustrates a
+typical block storage deployment where storage is provided by a stack of *block_store* components:
+
+.. image:: image/block-storage-layers.svg
+
+Some block devices supported in the TS project (located under:
+``components/service/block_storage/block_store/block_device``) are:
+
+ - **ram_block_store** - stores blocks in RAM. Intended for test purposes.
+ - **null_block_store** - a store with no real storage. Always accepts legal writes and returns
+ zeros for reads.
+ - **fvb_block_store** - an adapter that uses a UEFI firmware volume block driver to access
+ storage. Can be used with drivers from the EDK2 project.
+
+Other supported block_store components:
+
+ - **partitioned_block_store** - a stackable *block_store* that presents an underlying *block_store*
+ as a set of configurable storage partitions.
+ - **block_storage_client** - communicates with a remote block storage service provider to provide
+ storage.
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/service-descriptions/crypto-service-description.rst b/docs/services/crypto-service-description.rst
index 717c73b55..17a041d7a 100644
--- a/docs/developer/service-descriptions/crypto-service-description.rst
+++ b/docs/services/crypto-service-description.rst
@@ -1,7 +1,7 @@
-Crypto Service Description
-==========================
-Service Overview
-----------------
+Crypto Service
+==============
+Overview
+--------
The Crypto service provides a rich set of cryptographic operations with the backing
of a private key store. Clients identify keys using opaque key handles, enabling
cryptographic operations to be performed without exposing key values beyond the
@@ -80,6 +80,6 @@ only implementation is provided.
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/services/fwu/fwu-gpt-disk-image.rst b/docs/services/fwu/fwu-gpt-disk-image.rst
new file mode 100644
index 000000000..f83c4dd36
--- /dev/null
+++ b/docs/services/fwu/fwu-gpt-disk-image.rst
@@ -0,0 +1,6 @@
+.. include:: ../../../components/media/disk/disk_images/readme.rst
+
+..
+ *Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.*
+
+ SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file
diff --git a/docs/services/fwu/fwu-service-description.rst b/docs/services/fwu/fwu-service-description.rst
new file mode 100644
index 000000000..0fbc384bd
--- /dev/null
+++ b/docs/services/fwu/fwu-service-description.rst
@@ -0,0 +1,565 @@
+Overview
+--------
+The ability to update device firmware and related resources is a key requirement for
+maintaining security over a device's lifetime. Keeping firmware up-to-date with security
+fixes and feature enhancements is important for defending against emerging threats.
+Because firmware forms the security foundation of a device, it is important to apply
+updates in a timely manner to minimize risks exposed by firmware vulnerabilities. Any
+remote firmware update mechanism carries a risk of failure. As firmware is critical to
+the operation of a device, failures during the update process that lead to corrupted
+firmware have the potential to be highly disruptive. Any update mechanism intended
+for use with a large population of devices must offer robustness guarantees sufficient
+to keep the risk of failure at an acceptable level.
+
+Firmware update support within the Trusted Services project consists of a set of reusable
+firmware components that can be deployed within different execution environments to enable
+platform integrators to create firmware update solutions, tailored for their platform.
+The components are intended to be integrated into platform firmware and will be used in
+conjunction with a third-party update client, such as mender, swupd or fwupd, to create
+an end-to-end solution. The features supported aim to meet requirements for robustness
+and security. These include:
+
+ - Banked A/B robust update support
+ - Transactional multi-component updates with ACID (Atomicity, Consistency, Isolation,
+ Durability) guarantees
+ - Partial updates where not all components are updated
+ - Trial of an update with bootloader or client initiated rollback
+ - Anti-rollback counter management
+ - Standardized signaling to bootloader via the FWU Metadata structure
+ - Flexible installer framework to support different image types
+ - Image directory for advertising updatable components
+ - Compatible with UEFI FMP capsule update model and ESRT
+
+To support test and development and to provide a useful reference, the Trusted Services
+project maintains a reference integration with the following characteristics:
+
+ - Dual flash system where firmware is loaded from a dedicated secure world flash device.
+ - Secure flash is formatted with UEFI MBR/GPT with separate partitions for FWU metadata
+ and firmware banks.
+ - TF-A is used as the bootloader with separate firmware components packaged in a FIP
+ image.
+ - The Update Agent runs within a secure partition and exposes an FF-A based ABI that
+ conforms to the `Arm FWU-A specification`_.
+ - Test and development on supported :ref:`Target Platforms`.
+
+Source Code Location
+--------------------
+Within the Trusted Services project, source code related to FWU can be found under the
+following subdirectories (relative to the project root).
+
+.. list-table::
+ :header-rows: 1
+
+ * - Directory
+ - Contains
+ * - components/service/fwu
+ - Service components for implementing the FWU service provider.
+ * - protocols/service/fwu
+ - Public service access protocol (ABI) definition.
+ * - components/media/volume
+ - Storage volume access.
+
+Testing is covered in more detail in a later section. However, if you want a simple way
+of building and testing FWU components, the component-test deployment may be built for a
+native PC environment. The built executable includes an extensive set of FWU related tests
+that exercise the core Update Agent in various configurations. To build and run these tests
+on a Linux PC, use the following (from TS root directory):
+
+.. code-block:: bash
+
+ mkdir -p ~/compt-linux-pc
+ cmake -S deployments/component-test/linux-pc -B ~/compt-linux-pc
+ cmake --build ~/compt-linux-pc
+ ~/compt-linux-pc/component-test -v -g Fwu
+
+Output will look like this::
+
+ TEST(FwuCopyInstallerTests, installAndCopy) - 1 ms
+ TEST(FwuRawInstallerTests, normalInstallFlow) - 1 ms
+ TEST(FwuMetadataManagerTests, checkAndRepairInaccessibleStorage) - 0 ms
+ TEST(FwuMetadataManagerTests, checkAndRepairAccessibleStorage) - 1 ms
+ TEST(FwuRollbackTests, bootloaderFallback) - 0 ms
+ TEST(FwuRollbackTests, selectPreviousAfterActivation) - 0 ms
+ TEST(FwuRollbackTests, selectPreviousPriorToActivation) - 0 ms
+ TEST(FwuPowerFailureTests, powerFailureDuringTrial) - 0 ms
+ TEST(FwuPowerFailureTests, powerFailureDuringStaging) - 0 ms
+ TEST(FwuUpdateScenarioTests, partialFirmwareUpdateFlow) - 0 ms
+ TEST(FwuUpdateScenarioTests, wholeFirmwareUpdateFlow) - 0 ms
+ TEST(FwuInvalidBehaviourTests, invalidOperationsInTrial) - 0 ms
+ TEST(FwuInvalidBehaviourTests, invalidOperationsInStaging) - 0 ms
+ TEST(FwuInvalidBehaviourTests, invalidOperationsInRegular) - 0 ms
+ TEST(FwuImageDirectoryTests, zeroFwLocations) - 0 ms
+ TEST(FwuImageDirectoryTests, multipleFwLocations) - 0 ms
+ TEST(FwuImageDirectoryTests, singleFwLocation) - 1 ms
+ TEST(FwuImageDirectoryTests, streamRecycling) - 0 ms
+ TEST(FwuImageDirectoryTests, streamedReads) - 0 ms
+
+ OK (234 tests, 19 ran, 3452 checks, 0 ignored, 215 filtered out, 5 ms)
+
+Concepts and Assumptions
+------------------------
+Before describing details of the design, some important concepts and assumptions are
+introduced in this section.
+
+Update Packaging
+''''''''''''''''
+A set of firmware images that forms an update will be packaged in some way to enable
+it to be delivered to a device for installation. No particular packaging method is assumed
+by the FWU Update Agent. Any unpacking will be performed before individual images are
+presented to the FWU service for installation. The only assumption that the Update Agent
+relies on is that each image is identified by an image type UUID/GUID. The UEFI specification
+defines the FMP Capsule format that acts as a container for a set of arbitrary images. The
+reference integration maintained by the Trusted Services project uses UEFI FMP capsules
+but the FWU service can be used with any packaging method.
+
+Transactional Updates
+'''''''''''''''''''''
+A firmware update package may contain multiple images that all need to be installed as a
+set in order to successfully update a device's firmware. To avoid the hazard of booting
+a device using partially installed firmware, the FWU-A specification supports transactional
+updates where as set of separate image install operations are grouped together to form a
+single update transaction. The FWU-A specification defines a behavioral model where images
+are installed during the *STAGING* state. Entry to the *STAGING* state is triggered by the
+client making the ``fwu_begin_staging`` ABI call. This is followed a set of one or more install
+operations where images are written to the Update Agent. After committing the final image
+in the set, the client marks the end of the transaction by calling ``fwu_end_staging``.
+
+Banked Firmware Store
+'''''''''''''''''''''
+To offer the guarantee that device firmware is never left in an unbootable state, a valid
+version of firmware is always held in flash. Flash storage is organized into A and B banks
+where one bank holds a valid set of images while updates are installed in the other bank.
+The bootloader is capable of booting from either bank, as instructed by the FWU metadata
+written by the Update Agent. Where firmware storage is distributed across multiple locations,
+A and B volumes must exist for each location.
+
+Update Agent
+''''''''''''
+The Update Agent is a logical component defined in the FWU-A specification reference model.
+The Update Agent handles requests from a client to install a set of images in preparation
+for activating the updated firmware. In the TS project, the role of the Update Agent is
+reflected by a firmware component with the same name.
+
+Firmware Directory
+''''''''''''''''''
+The FWU-A specification defines a stream endpoint that can be read by a client to obtain a
+listing of updatable firmware components. In the TS implementation, this is backed by the
+Firmware Directory component that is populated with information about the booted firmware.
+
+Storage Volumes
+''''''''''''''''
+All NV storage accessed by the Update Agent is represented by a set of volume objects. A
+volume presents a unit of storage as a seekable file with support for conventional file IO
+operations. The volume provides a uniform interface for all storage operations performed by
+the Update Agent. The volume uses and extends the *io_dev* driver model from the TF-A project.
+Concrete volume objects can access different types of storage such as:
+
+ - A raw flash device
+ - A disk partition
+ - Storage managed by a subsystem
+
+Installers
+''''''''''
+Trusted Services FWU support provides a framework for updating arbitrary firmware images.
+From the framework's perspective, an image is just a binary blob, identified by an image
+type UUID. To allow for image format specific installation, a common installer interface is
+defined to allow for alternative concrete installers. Installers can update the entire
+contents of a volume or modify parts of a volume. Where a volume holds a container such
+as a FIP, a specialized installer with knowledge of the container format can provide finer
+grain updates of the container contents. An installer implements an enumerate method to
+return information about images that it can handle. The Firmware Directory is formed by
+aggregating the information returned by each installer's enumerate method.
+
+Firmware Locations
+''''''''''''''''''
+The Update Agent can manage firmware distributed across multiple locations e.g. different
+flash partitions, different flash devices or different subsystems. The concept of a firmware
+location is used in the TS implementation to provide a generalized model for handling
+distributed firmware. Each location is assigned an integer ID that is used to bind together:
+
+ - A pair of storage volumes (for A + B banks)
+ - A set of one or more installers. The set of installers configured for the location
+ determines which image types are updatable for the location.
+
+Installers are categorized as one of the following types:
+
+ - **Whole volume installer** - updates the entire contents of a volume. The whole volume
+ contents is presented as an entry in the firmware directory.
+ - **Sub-volume installer** - updates components contained within a volume. Each image
+ contained within the active volume is presented as an entry in the firmware directory.
+ - **Whole volume copy installer** - copies entire volume contents from one volume to
+ another. Contributes no entries to the firmware directory.
+
+A platform integrator is responsible for selecting which installers are configured for a
+location. Each location must be assigned at least one installer. Any combination of different
+types of installer could make sense in a platform configuration. Here are some example
+configurations:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Location configuration
+ - Update capability for location
+ * - *WholeVolumeInstaller*
+ - A single entry appears in the firmware directory for the location that corresponds to
+ the entire volume contents. An incoming update package must include an image that
+ corresponds to the directory entry.
+ * - *WholeVolumeInstaller + SubVolumeInstaller*
+ - Firmware directory entries appear for the whole volume and for each updatable component
+ contained within the volume. An incoming update package must include either one or more
+ sub-volume images or a whole volume image for this location.
+ * - *WholeVolumeInstaller + SubVolumeInstaller + WholeVolumeCopyInstaller*
+ - Firmware directory entries appear for the whole volume and for each updatable component
+ contained within the volume. If no image for this location is included in an incoming
+ update package, the currently active volume contents is copied to the update volume.
+ * - *WholeVolumeCopyInstaller*
+ - This configuration can be used if it is necessary to prevent updates for a location.
+ For any update transaction, the currently active volume contents will always be copied
+ to the update volume for this location.
+
+Design Description
+------------------
+FWU components within the TS project are designed for reuse in alternative deployments. The
+project currently maintains two FWU deployments, both sharing many common components:
+
+ - **fwu/config/default-sp** - the Update Agent runs within a secure partition. The client
+ invokes ABI operations via FF-A based RPC. Updates are applied to a dedicated SWd flash device.
+ - **fwu-tool/linux-pc** - the Update Agent runs within a command-line application.
+ Updates are applied to a disk image file residing in the host filesystem.
+
+There is clear separation between different classes of component making component-level reuse
+straight-forward. The following diagram illustrates the main FWU components. The direction of
+the arrows linking components shows the direction of a dependency between associated
+components (i.e. A→B means that A depends on B).
+
+.. image:: ../image/update-agent-components.svg
+
+Core Components
+''''''''''''''''
+Any FWU deployment that supports a banked firmware store is expected to use the core set of
+FWU components. Core components are partitioned between:
+
+ - **Generic Update Agent** - manages update transactions and streams used for transferring
+ image data. Also owns the FW Directory.
+ - **Banked FW Store** - manages banked access to storage and communication with the bootloader
+ via FWU metadata.
+
+Generic Update Agent Model
+""""""""""""""""""""""""""
+The following class diagram models the generic Update Agent:
+
+.. uml:: ../uml/UpdateAgentClassDiagram.puml
+
+Classes in the model perform the following roles:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Class
+ - Description
+ - Source files
+ * - *update_agent*
+ - Coordinates update transactions from start to finish. Implements the FWU state machine that
+ enforces correct behaviour during an update. Provides functions that form the public interface
+ for an instance of the Update Agent.
+ - components/service/fwu/agent/update_agent.h, components/service/fwu/agent/update_agent.c
+ * - *stream_manager*
+ - Manages a pool of stream objects for client initiated stream read and write operations. Streams
+ are used for writing image data and reading FWU objects such as the image directory.
+ - components/service/fwu/agent/stream_manager.h, components/service/fwu/agent/stream_manager.c
+ * - *fw_directory*
+ - Holds information about the currently active firmware. The contents of the fw_directory is
+ updated by a fw_inspector at boot time. Forms the source of the information returned to a
+ client that reads the image directory object.
+ - components/service/fwu/agent/fw_directory.h, components/service/fwu/agent/fw_directory.c
+ * - *img_dir_serializer*
+ - Serializes information about currently active firmware in-line with the FWU-A specification.
+ - components/service/fwu/agent/img_dir_serializer.h, components/service/fwu/agent/img_dir_serializer.c
+ * - *fw_inspector*
+ - Called by the update_agent to inspect firmware and update the contents of the fw_directory to
+ provide a fresh view of active firmware. To allow for alternative inspection strategies, the
+ concrete fw_inspector to use is determined by deployment specific configuration code and passed
+ to the update_agent at initialization. The direct_fw_inspector is a concrete fw_inspector that
+ relies on direct access to the set of installers registered as part of the Update Agent configuration.
+ - components/service/fwu/inspector/fw_inspector.h, components/service/fwu/inspector/direct/direct_fw_inspector.h,
+ components/service/fwu/inspector/direct/direct_fw_inspector.c
+
+Banked FW Store Model
+""""""""""""""""""""""
+The update_agent interacts with the fw_store via a common interface. No details about the nature of the fw_store
+are exposed to the update_agent. The following class diagram models a particular realization of the fw_store
+interface that implements the A/B bank scheme:
+
+.. uml:: ../uml/FwStoreClassDiagram.puml
+
+Classes in the model perform the following roles:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Class
+ - Description
+ - Source files
+ * - *fw_store*
+ - Manages updates to banked storage volumes.
+ - components/service/fwu/fw_store/fw_store.h,
+ components/service/fwu/fw_store/banked/banked_fw_store.h,
+ components/service/fwu/fw_store/banked/banked_fw_store.c
+ * - *bank_tracker*
+ - Tracks usage and accepted state of firmware banks.
+ - components/service/fwu/fw_store/banked/bank_tracker.h,
+ components/service/fwu/fw_store/banked/bank_tracker.c
+ * - *metadata_manager*
+ - Manages storage and updates to the FWU metadata used for signaling to the bootloader. Responsible for
+ detecting and repairing corrupted metadata.
+ - components/service/fwu/fw_store/banked/metadata_manager.h,
+ components/service/fwu/fw_store/banked/metadata_manager.c
+ * - *metadata_serializer*
+ - Serializes update bank state in a standard format for compatibility with the boot loader. To ensure
+ version compatibility through fw updates, alternative realizations of the metadata_serializer may be
+ selected at runtime. Currently support for V1 and V2 formats (as defined by the FWU-A specification).
+ - components/service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h
+ * - *installer*
+ - Base class for installers. Defines a common interface for installing images associated with a location.
+ - components/service/fwu/installer/installer.h,
+ components/service/fwu/installer/installer.c
+ * - *installer_index*
+ - Holds pointers to the set of concrete installers registered during platform configuration.
+ - components/service/fwu/installer/installer_index.h,
+ components/service/fwu/installer/installer_index.c
+ * - *volume*
+ - Presents a unit of storage is a seekable file. Supports byte-orient read and writes operation
+ to storage. All NV storage is accessed by the Update Agent using volumes. The set of volume objects
+ needed for a deployment are created as part of platform specific initialisation.
+ - components/media/volume/volume.h,
+ components/media/volume/volume.c
+ * - *volume_index*
+ - Holds pointers to the set of concrete volumes registered during platform configuration.
+ - components/media/volume/index/volume_index.h,
+ components/media/volume/index/volume_index.c
+
+Service Interface
+''''''''''''''''''
+For deployments where the Update Agent needs to be remotely callable, the fwu_provider implements an
+RPC interface that accepts call requests, de-serializes call parameters and calls the corresponding
+interface functions provided by the update_agent. In the reference deployment, where the Update
+Agent runs within an SP, the fwu_provider receives call requests, made via FF-A, and returns responses
+to the remote client. The fwu_provider may be used with any RPC layer where remote calling is required.
+
+Platform Configuration
+----------------------
+A platform specific configuration tells the Update Agent about storage for firmware and defines the
+policy for the way the firmware can be update. Configuration steps result in the creation of:
+
+ - A set of concrete installer objects registered with the installer_index. This defines the
+ type of images that can be updated.
+ - A set of concrete volume objects registered with the volume_index. This defines where images
+ can be installed.
+
+Each installer is assigned a location ID to bind the installer to a particular firmware location.
+Location IDs are integer values defined by the configuration code. For example, where firmware
+consists of AP firmware, SCP firmware and RSS firmware, location IDs could be assigned as follows:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Location
+ - ID
+ * - AP firmware
+ - 0
+ * - SCP firmware
+ - 1
+ * - RSS firmware
+ - 2
+
+When volume objects are added to the volume index, each one is assigned a volume ID which is
+formed by combining the corresponding location ID with the bank index to which the volume
+provides access to.
+
+The types of installer and volume needed will depend on factors such as:
+
+ - How NV storage is accessed by the Update Agent.
+ - The type of images that need to be installed.
+ - How flash storage is partitioned e.g. is GPT used or some other partition description method.
+
+Source files related to FWU configuration:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Directory
+ - Contains
+ * - components/service/fwu/config
+ - Configuration strategies for provisioning installers and volumes
+ * - components/service/fwu/installer/factory
+ - Factories for constructing different types of installer
+ * - components/media/volume/factory
+ - Factories for constructing different types of volume
+
+Update Agent Configuration using GPT
+''''''''''''''''''''''''''''''''''''
+The TS FWU service implementation includes a GPT based configurator that automatically discovers
+the set of installers and volumes to construct, based on the contents of the GPT that describes
+the flash layout. The following diagram illustrates a typical flash partition layout. Note that
+not all partitions contain firmware.
+
+.. image:: ../image/gpt-based-flash-layout.svg
+
+A deployment of the Update Agent is built with an installer factory that has the capability to
+construct a set of installers that are suitable for a family of platforms where common image
+types and update policy applies. An installer factory is capable of constructing a concrete set
+of installers for installing images into a particular set of partitions, identified by partition
+type GUID. A platform may not incorporate the complete set of partition types. The default
+installer factory (under components/service/fwu/installer/factory/default) includes rules for
+constructing installers for:
+
+ - **AP Firmware** - where application firmware is contained within a FIP
+ - **SCP Firmware** - binary boot image for SCP
+ - **RSS Firmware** - binary boot image for RSS
+
+The GPT based configurator relies on access to the GPT partition table. During initialization
+of the Update Agent, the configurator iterates over each partition entry. If no installers are
+registered for the partition, the partition type GUID is offered to the installer factory. If
+at least one installer is constructed, a volume object is constructed to provide access to the
+partition. This partition will hold one of the banked copies of the image identified by the
+partition type GUID. If one or more installers have already been constructed for the partition
+type GUID, an additional volume object is constructed to provide access to the second
+banked partition.
+
+The designation of bank index to partition is determined from the PartitionName field in the
+partition entry. The first UTF-16 character (0 or 1) is interpreted as the bank index assigned
+to the partition. Different conventions are possible if an alternative configurator is used.
+
+FWU Command Line Application
+----------------------------
+The *fwu-tool* deployment integrates the Update Agent within a command-line application that can be
+run on a Linux PC. Instead of updating images stored in flash, the application operates on a GPT
+formatted disk image file residing in the host machine's filesystem. (Refer to :ref:`UEFI disk image
+creation instructions` to see how a disk image can be created.) The core components of the
+application are identical to those used in embedded deployments. To build and run the fwu
+application, use the following commands from the root of the checked-out TS project:
+
+.. code-block:: bash
+
+ mkdir -p ~/fwu-tool
+ cmake -S deployments/fwu-tool/linux-pc -B ~/fwu-tool
+ cmake --build ~/fwu-tool
+
+ ~/fwu-tool/fwu-tool -h
+ Usage: fwu disk-filename [-dir -meta] [-boot-index number -meta-ver number] [-img filename -img-type uuid]
+
+ disk-filename Disk image file to update
+ -dir Print image directory
+ -meta Print FWU metadata
+ -boot-index Override default boot index [0..n]
+ -meta-ver Specify FWU metadata to use
+ -img File containing image update
+ -img-type Canonical UUID of image to update
+
+Some sample disk image files can be found under ``components/media/disk/disk_images``
+
+The sample disk image file *multi_location_fw.img* includes a GPT with entries for the firmware
+and metadata partitions illustrated in the diagram above. Note that the sample disk image
+does not contain valid FWU metadata within the primary and backup metadata partitions. This
+condition is detected by the Update Agent which writes valid metadata that reflects the contents
+of the disk image file. Subsequent invocations of the app will use the valid metadata previously
+written to the disk image.
+
+The app can of course be used with flash image files created by a firmware build system.
+The command-line interface currently restricts updates to consist of just a single image,
+identified by an image type UUID. Extending the command-line interface to support multi-image
+update transactions is possible by for example adding the capability to process an FMP capsule
+file containing multiple images.
+
+Testing the Update Agent
+------------------------
+FWU components are tested in both native PC and embedded environments. PC based tests use the
+*fwu_dut* C++ class to simulate the role of the bootloader and to allow device reboot scenarios
+to be recreated. The simulated device-under-test maintains NV storage state through reboots
+to mimic real device behaviour. Test components that support PC based testing are summarized
+in the following table:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Component
+ - Description
+ - Project Directory
+ * - *fwu_dut*
+ - Base class to represent a device-under-test (DUT). Presents an interface used by test
+ cases that allows for test-case reuse with different fwu_dut specializations.
+ - components/service/fwu/test/fwu_dut
+ * - *sim_fwu_dut*
+ - A specialization of the fwu_dut class that adds bootloader simulation and various
+ other test support capabilities.
+ - components/service/fwu/test/fwu_dut/sim
+ * - *proxy_fwu_dut*
+ - A specialization of the fwu_dut class that acts as a proxy for the fwu_dut that
+ actually hosts the Update Agent.
+ - components/service/fwu/test/fwu_dut/proxy
+ * - *fwu_client*
+ - Presents FWU methods (begin_staging, end_staging etc.) for use by test cases.
+ - components/service/fwu/test/fwu_client
+ * - *direct_fwu_client*
+ - An fwu_client that calls Update Agent interface functions directly.
+ - components/service/fwu/test/fwu_client/direct
+ * - *remote_fwu_client*
+ - An fwu_client that makes RPC call requests to invoke Update Agent operations. Call
+ parameters are serialized using the FWU access protocol.
+ - components/service/fwu/test/fwu_client/remote
+ * - *image_directory_checker*
+ - A test support class that fetches the serialized image directory and provides
+ methods for checking the fetched content.
+ - components/service/fwu/test/image_directory_checker
+ * - *metadata_checker*
+ - Provides methods to check that the fetched FWU metadata reflects the state expected
+ by test cases. Decouples test code from the underlying metadata format. Support
+ for V1 and V2 metadata is provided.
+ - components/service/fwu/test/metadata_checker
+ * - *metadata_fetcher*
+ - Provides an interface for fetching the metadata associated with the DUT. Depending
+ on the deployment, different strategies for fetching the metadata are needed.
+ - components/service/fwu/test/metadata_fetcher
+
+An extensive set of test suites uses the test framework components listed above to test
+various update scenarios. The following test suites live under ``components/service/fwu/test/ref_scenarios``
+
+.. list-table::
+ :header-rows: 1
+
+ * - Test Suite
+ - Description
+ * - *image_directory_tests*
+ - Tests reading of the image directory via the Update Agent stream interface.
+ * - *invalid_behaviour_tests*
+ - Tests to check that invalid requests are rejected with the expected error codes.
+ * - *oversize_image_tests*
+ - Tests to check defenses against attempts to install images that are too big for
+ the available storage.
+ * - *power_failure_tests*
+ - Tests recreate power-failure scenarios at various points during an update transaction.
+ Tests check that a viable set of firmware is always available.
+ * - *rollback_tests*
+ - Tests recreate bootloader initiated and update client requested rollback scenarios.
+ * - *update_scenario_tests*
+ - Various normal update scenarios with a well-behaved client.
+
+The test suites list above are included in the following TS test deployments:
+
+ - **component-test** - runs tests in a native PC environment using a *direct_fwu_client*.
+ - **ts-service-test** - runs tests in a native PC environment using a *remote_fwu_client*.
+
+Reference Integration Test Environment
+--------------------------------------
+The following diagram provides an overview of the planned reference integration and test
+environment used for testing on FVP.
+
+.. image:: ../image/fwu-reference-integration.svg
+
+--------------
+
+_`Arm FWU-A specification`: https://developer.arm.com/documentation/den0118
+
+*Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/services/fwu/index.rst b/docs/services/fwu/index.rst
new file mode 100644
index 000000000..804244553
--- /dev/null
+++ b/docs/services/fwu/index.rst
@@ -0,0 +1,15 @@
+Firmware Update Service
+=======================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents:
+
+ fwu-service-description
+ fwu-gpt-disk-image
+
+--------------
+
+*Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/services/image/block-storage-example-usage.svg b/docs/services/image/block-storage-example-usage.svg
new file mode 100644
index 000000000..5da742797
--- /dev/null
+++ b/docs/services/image/block-storage-example-usage.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="921px" height="551px" viewBox="-0.5 -0.5 921 551" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2022-08-25T16:15:08.782Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;mAY4xjS1y1Ce76DsL9WA&quot; version=&quot;20.1.4&quot; type=&quot;atlas&quot;&gt;&lt;mxAtlasLibraries/&gt;&lt;diagram id=&quot;plxMLLH-skr558P6A1ZB&quot; name=&quot;Page-1&quot;&gt;3VrbctowEP0aHunYFubyyDWdJkyY0k5KXjqKLWwNwmJkESBfXxnLV5lLCdSmT1hH0gqdPdr1Cmqgv9w+MLhyx9RGpGZo9rYGBjXD0DsAiI8A2YVIGzRCwGHYloMSYIo/kAQ1ia6xjfzMQE4p4XiVBS3qecjiGQwyRjfZYXNKsquuoCNX1BJgakGClGEv2Oau3IWZGv0VYceNVtY12bOE0WAJ+C606SYFgWEN9BmlPHxabvuIBORFvITzRgd64y/GkMfPmTBv7Zzxyuqw2XjDtfaH/mrCuhFaeYdkLTcsvyzfRQwwuvZsFBjRa6C3cTFH0xW0gt6N8LnAXL4ksnuOCelTQtl+LrAhas8tgfuc0QWKejzqiek9dQdyU++IcbRNQXJHD4guEWc7MUT21vWmpFfqK2J7kzgrHuKmHdWWIJQCcWLbCYfiQdJYTOmju/6tdRmZ6LPm2+IbefrOaF2/d0pblaNUVemUj8dHaNVO03oVphpZppqmypRRwFTnCkQ96QuwaDuzH5OXwSvt9Qh/9O5fe2aZ2iukVNXehFEuUo3g0NCmnLIgg5QuRbNqUgT3LkVQOSk2FEqfJ/Ufw2H56gNVU5957+pTAmG7dPk1FU57hFqLKkdBYJQtxJZC2gDZ2IJh+hgR6LsKbaJSWAWP1o5gwR8Dp8l7C5l+eosBaC2cPf/Pay7MIIn7YYWlm9diXM8y3uioOi2S6c1U2j598pFnd4PSMDmxKSbRFvNfgWK/mLI1k/oNngfbdGOXakwQw2IHiEWYJ3aTMhQ0Z9EaQSMxtW9Ftg46xadrZqHTUuOQOYifPsfIjirfAy5OedAs8GCEMUQgx+/ZernIrXKFCcViZ4mCjFykA3lphBuX09IFrmIpp0UAcpZCahRLe53FG79cep1PSu+g66viKqUybFzoqsYJOzd2VKSTlKdGo3pXIGPk+9DBnqN4TgREnnVXYe5PvyhICBLseEE4F24NwkMvCK8iBZCu7Fhi2w6WKQzy2Rx6hZBt5rgHBS8WeoGIjFtFbP2MqvV4yL52qD0ZQhvVOpdxNv3suVRDaN7rtz6Zarn9b7RwSdq/PFU3z9SZUTGd5VN16251dsb1RHkx59glaFW00Px/Yo56rzKBIkNzTD0B96k3x86awbB9oFazqbVe7n3616XaFXK6cgEDCrJ6p0ANNyvD9DNuYNQDZotyOL6SKSjK9HRsjiN1WdFZr9prwD2G58KfJdU3wp8rG3IksK6D5Jql3jTpJd54FlJW6YR2zMlVOT3Xy2c5Q6Z5pbMjmsnfBcLhyZ8uwPAP&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><rect x="600" y="0" width="160" height="180" rx="24" ry="24" fill="#dae8fc" stroke="none" pointer-events="all"/><rect x="0" y="0" width="160" height="180" rx="24" ry="24" fill="#dae8fc" stroke="none" pointer-events="all"/><rect x="20" y="45" width="120" height="90" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 90px; margin-left: 21px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">StMM</div></div></div></foreignObject><text x="80" y="94" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">StMM</text></switch></g><rect x="200" y="0" width="160" height="180" rx="24" ry="24" fill="#dae8fc" stroke="none" pointer-events="all"/><rect x="220" y="45" width="120" height="90" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 90px; margin-left: 221px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Protected Storage</div></div></div></foreignObject><text x="280" y="94" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Protected Storage</text></switch></g><rect x="400" y="0" width="160" height="180" rx="24" ry="24" fill="#dae8fc" stroke="none" pointer-events="all"/><rect x="420" y="45" width="120" height="90" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 90px; margin-left: 421px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">OP-TEE</div></div></div></foreignObject><text x="480" y="94" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">OP-TEE</text></switch></g><rect x="200" y="260" width="160" height="180" rx="24" ry="24" fill="#dae8fc" stroke="none" pointer-events="all"/><rect x="220" y="305" width="120" height="90" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 350px; margin-left: 221px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Block Storage</div></div></div></foreignObject><text x="280" y="354" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Block Storage</text></switch></g><path d="M 250 485 C 250 476.72 263.43 470 280 470 C 287.96 470 295.59 471.58 301.21 474.39 C 306.84 477.21 310 481.02 310 485 L 310 535 C 310 543.28 296.57 550 280 550 C 263.43 550 250 543.28 250 535 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 310 485 C 310 493.28 296.57 500 280 500 C 263.43 500 250 493.28 250 485" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 523px; margin-left: 251px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Dedicated Flash</div></div></div></foreignObject><text x="280" y="526" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Dedicated...</text></switch></g><path d="M 280 470 L 280 395" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 0 220 L 800 220" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><rect x="810" y="210" width="110" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 220px; margin-left: 811px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FF-A Messaging</div></div></div></foreignObject><text x="865" y="224" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">FF-A Messaging</text></switch></g><path d="M 480 220 L 480 135" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 280 305 L 280 135" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 80 220 L 80 135" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 420 310 L 510 310 L 510 378 Q 487.5 356.4 465 378 Q 442.5 399.6 420 378 L 420 322 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 338px; margin-left: 421px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Partition Configuration</div></div></div></foreignObject><text x="465" y="342" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Partition Confi...</text></switch></g><path d="M 340 350 L 420 350" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><rect x="620" y="45" width="120" height="90" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 90px; margin-left: 621px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Update Agent</div></div></div></foreignObject><text x="680" y="94" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Update Agent</text></switch></g><path d="M 680 220 L 680 135" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/services/image/block-storage-layers.svg b/docs/services/image/block-storage-layers.svg
new file mode 100644
index 000000000..f7aa6e35a
--- /dev/null
+++ b/docs/services/image/block-storage-layers.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="701px" height="371px" viewBox="-0.5 -0.5 701 371" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2022-09-01T13:39:56.084Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;5wmKJudSRu0eKebtsNFl&quot; version=&quot;20.1.4&quot; type=&quot;atlas&quot;&gt;&lt;mxAtlasLibraries/&gt;&lt;diagram id=&quot;3S9PIcjPeEhHK4FUF1jD&quot; name=&quot;Page-1&quot;&gt;7ZhLb+IwEMc/DUdWeROONECrqlXZUmmXvVQmNomLE0eOeWQ//TrEIU8erVK1hz0R/+2M7d/M2BN6uhPsbxmI/EcKEelpCtz39HFP09ShroufVEkyxdCNTPAYhnJQIczxXyRFRaobDFFcGcgpJRxHVdGlYYhcXtEAY3RXHbaipDprBDw5o1IIcxcQ1Bj2C0PuZ6ptlkbfIez5+cyqInsCkA+WQuwDSHclSZ/0dIdRyrOnYO8gksLLuWTvTU/0HhfGUMiveYGrTwYcBM+W9vLzxrRHizeH9aWVLSAbuWG5WJ7kBBjdhBClRtSefrPzMUfzCLhp7074XGg+D4jsXmFCHEooO7yrQ4DslSv0mDO6RqUey7XRciV6mtvI14QYR/uSJLd1i2iAOEvEENnb1wzJWAaZOZDtXeEy3ZaaX3KXlvsRyDDxjsYLkuJBwnwHWKsBdkmou36NOWUiZl4jRrcistkZ3Mpl3J3AU6vwLKUFntYCz/osdvmCSvCeZ8KUMglhRLHY6veD1hJxwxZmqt4BtKe3+3k4DRxk+6OJc+8l1i+/rzeYiR1yzDENEXwtgg99PbzhZXaa8kkB9+dl/fB8a+4WwXj58JhsvMXgvuUUzHhBtMXu9wM2ML4amNYA5hCMzibmt708DLMWjlaTrjpooTv8LLrNVG5wRSEcpdWNaLkExDF2qyirIYr2mP9On38Ylinbi0N7aA9le7wvDR4npcYMMSw2hliuhWKTmTkzby7kvIdGYerQym2ddFZMN8xFl8ONA+YhfsXFgWBe1J3wfcm1Zotnc40hAjjeVkvBNnfLGWbZ5ZSHVu2OGNbP/mzfs+ONNj1hx6rase2anYxLw44IEJCUhh2uzvj0cvv6oDaRqZxdV18V0XTmBfGQraFIhaMPPp4dRiM7piID/EaKiHo7Sh/dhGCRC0y/fAAts6x5WB4F4K69Qy49bbgwg6QeZ98pqtlVOVED33IEWS1xWg+Ezk4gs+sT6OO5n3/0lXL/XFj8T/0uc635FXM6zTaMJDdMJEzqpkuZVq0LVgRHd93VS6p1TYHZ9H0nxXkrx0GDY6UgFzwFtwZasV1exVathEKaHkiVsklKgGAvTJ0iIKb39k0KD7uAjGRHgCFMp2n105Wp+w6H1AtY7brz7QP+EM3iL5UsDYo/pvTJPw==&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><rect x="210" y="0" width="380" height="250" rx="37.5" ry="37.5" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><rect x="240" y="30" width="320" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 318px; height: 1px; padding-top: 60px; margin-left: 241px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">block_storage_provider</div></div></div></foreignObject><text x="400" y="64" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">block_storage_provider</text></switch></g><rect x="240" y="100" width="90" height="130" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 165px; margin-left: 241px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">RPC Endpoint</div></div></div></foreignObject><text x="285" y="169" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">RPC Endpoint</text></switch></g><rect x="360" y="100" width="200" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 130px; margin-left: 361px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">partitioned_block_store</div></div></div></foreignObject><text x="460" y="134" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">partitioned_block_store</text></switch></g><rect x="360" y="170" width="200" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 200px; margin-left: 361px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">block_device</div></div></div></foreignObject><text x="460" y="204" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">block_device</text></switch></g><rect x="0" y="90" width="170" height="90" rx="13.5" ry="13.5" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 135px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Client</div></div></div></foreignObject><text x="85" y="139" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Client</text></switch></g><path d="M 79.05 179.01 L 80 280 L 285 280 L 285 236.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 285 231.12 L 288.5 238.12 L 285 236.37 L 281.5 238.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 430 305 C 430 296.72 443.43 290 460 290 C 467.96 290 475.59 291.58 481.21 294.39 C 486.84 297.21 490 301.02 490 305 L 490 355 C 490 363.28 476.57 370 460 370 C 443.43 370 430 363.28 430 355 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 490 305 C 490 313.28 476.57 320 460 320 C 443.43 320 430 313.28 430 305" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 343px; margin-left: 431px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Flash</div></div></div></foreignObject><text x="460" y="346" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Flash</text></switch></g><path d="M 460 230 L 460 283.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 460 288.88 L 456.5 281.88 L 460 283.63 L 463.5 281.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 630 100 L 625 100 Q 620 100 620 110 L 620 155 Q 620 165 615 165 L 612.5 165 Q 610 165 615 165 L 617.5 165 Q 620 165 620 175 L 620 220 Q 620 230 625 230 L 630 230" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="translate(620,0)scale(-1,1)translate(-620,0)" pointer-events="all"/><rect x="640" y="150" width="60" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 165px; margin-left: 641px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">block_store stack</div></div></div></foreignObject><text x="670" y="169" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">block_stor...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/services/image/fwu-reference-integration.svg b/docs/services/image/fwu-reference-integration.svg
new file mode 100644
index 000000000..e1decb0de
--- /dev/null
+++ b/docs/services/image/fwu-reference-integration.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="931px" height="721px" viewBox="-0.5 -0.5 931 721" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2023-02-16T09:53:31.669Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;zn_aC2t2yAJM8WazQzIG&quot; version=&quot;20.3.7&quot; type=&quot;atlas&quot;&gt;&lt;mxAtlasLibraries/&gt;&lt;diagram id=&quot;5UEW7cEHIPK3IHdKgyrX&quot; name=&quot;Page-1&quot;&gt;5Vtbd6I6FP41PrYLiNweq62dzpp22ml75pynrghRmAJxIGqdXz8JBIQkWnXE0Z4+WNm5EPb37Us2sQP68dt1CifBLfZR1DE0/60DLjuGobsA0H9MsuAS2zULyTgNfS5bCh7DX4gLNS6dhj7KGh0JxhEJJ02hh5MEeaQhg2mK581uIxw17zqBY35HbSl49GCEpG7fQ58EhdQxa70/oXAclHfWNd4Sw7IzF2QB9PG8JgJXHdBPMSbFt/itjyKmvVIvxbjBitZqYSlKyCYDHPLyI3Ptga2hK+MVOf1bVz8r1TyD0ZQ/8SecESq5hV4QJoivnSxKhcxQSkKqn4soHCdURPCkA3qQX0VoRBfTyybQC5PxE2u7dJaCL3nzpbGUfOO603NZACfsNt50iNhlwQa6RtDzw5TCG2J2kwxPmW57I5yQR76yLr0OSByx/qwpjKI+jnCaLxqM3JGNfDYlSfErqrUAC7iAtcjq5BpmD4zeaiKu3muEY0TSBe3CW8/MLlcnZ/uZBbhgvuSOW8qCGm/skiWQ83Vczb6ElH7hqG6BsCkBPPjn/mOgivK/1lE1LAFV0zYlVE1HgaqpmS2hqkuoXj4/nSiqe8FIEzFSWF7XUmAE7LYsrythJAGEEv+CBSl6leAENfWS4mniM691qeUchykROq/UHNV66pXm/uASoIO72cR5en2YPY8Xb59L/tA5x4iseQa+ZOSXUXIFDnVLUBpCIUtRBEk4a8ZWleL5He5xmJAlzLojoKx3BfCKB+fD6sFQmMkA4kyuMFOhGmmmnAnVg+9ODksixyiCWcCGxSwloalKGMnRt7S6GPtTJlthzKXtarUeHiUJov6xp/YK+7BCvfR3pVYN2QgNew0/9m6DjqTmDMVhQFMcqiVJu/Q5SdMGm5GFm109DHHRu0qOQ9/PAZsHIUGPFCZ2zznNmiVL3wMSupiI6JaMhNIbtgWEKwHxhDLiwezUOG4agmqBI2cD1S7gICTXt4s0HnU0WeitCzboLST/su/nJr/6r9Zy+Va/WJQXCX2WYpAO9FLAxunnmgZKwXJwftUYfY/SkKqEIbjeEurxbR3d3o1v5lHFN8olcQOxa4A7A2KEszaMcJQmcFHrNmEdsjWL7tpi7qW5AqeLOfcaQHV5Y5OnSHSyjFn7h/XtZ11T1Hf3Lzt33d67A6qcSd2RaGucCDBXeRG1M9PXOrP2PY91XJ7HEElliBWJnVNr41COh7uEdt2OnFFOJz4kKMfg55QmNRmDH7MMfs6+obycdnF/84FdEnAFzCsfVU+K9JZ80k1AerOB+5BNrp0sfbRfkvlCUSG5w2kM2bjvOI18CY3TKJYIJTDfRI7fVZXAHGMILGtfGzs5xCvKK6qkt9p47D3oGDLCdMcQjujMAw+n6XRCPrDFdcWipGKrrSpJtmZvhoTGI/KmKfpg9gaRM/JU9mZ5DhqO2rI3oChnAtc+NxUWt4995rqiYT30ZdQWDCtiUA3ZtzHJNWDBmIGZDDP2b5JiD2WZxICmVajsZgUQ3CZ9mAX5cNYewSGK7nEWcmwlQ/0idGjybaVdDzEhOP5DXKuwaClqBa7CTJ3WvKaE4Wj+wnKUFzgJJYSOuhQjZqzKnOOwhRi5qiupdLdCTLlbyXdB1T7mvULMn++dVsK0t30Q19CR7IOkNwzG3t4wtLYNAlKwsLS1S5NHdA+xdQKScTyXO6eLMUrkbO2kvI+heCl8WO/TYhHm3DY39SWHr7iADT3NcVVcjsDT7GDYytRfrsTuKeptw58aWbfi6u68MzbkHTgq3lVHvqRXg9vyTnzHWJ3ZOxDtZH/3BUNGIjouyQtwKJ5SXeWS8u06Tf0ZMWFKpm28I+CR6S8XBwzRtyheEBy4GifvHZ+vBjdUctt7ojNe3z8xkFiFjhSA+WH22lmehpiHJCj0QvINXFZ0p5+D78/0ky4T0mQCssUnOeBhGs9hXn8YwuQ1O/+oaEtHn1Rgq14HiVFiF7C1HzPXt+zPN+NfX3XrbrG4BSNFnSArS0EVfhIa/59iQNkqRW1FAqkq4bl7OFT407p6oFpM7q77/dep74zH8WdFgt7DmETMqaYSXkednJ9JB2AOmp4rtSsf0rhahqe7r9+YKyuC1GlpeuWZvPd43Jqm5bNGkk5PPB9dZ771fHQdEY8lH7Wls2piFrLxmRdLfA2pi3XU/aWkStUqfk4hUY9GwlkVqLbjYSPGVaSslwZXUlIvmSudjti6Wqi3UC20TpO7juj8dqauI27iN2Tu1tVCQ7QRp1Es3Lb0Ry+XP2Equi9/CQaufgM=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 105 -105 L 815 -105 L 825 -95 L 825 825 L 115 825 L 105 815 L 105 -105 Z" fill="#f9f7ed" stroke="#36393d" stroke-miterlimit="10" transform="rotate(90,465,360)" pointer-events="all"/><path d="M 115 825 L 115 -95 L 105 -105 M 115 -95 L 825 -95" fill="none" stroke="#36393d" stroke-miterlimit="10" transform="rotate(90,465,360)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 15px; margin-left: 4px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: nowrap;">Host Machine</div></div></div></foreignObject><text x="4" y="27" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-decoration="underline">Host Machine</text></switch></g><path d="M 317.5 17.5 L 812.5 17.5 L 822.5 27.5 L 822.5 597.5 L 327.5 597.5 L 317.5 587.5 L 317.5 17.5 Z" fill="#eeeeee" stroke="#36393d" stroke-miterlimit="10" transform="rotate(90,570,307.5)" pointer-events="all"/><path d="M 327.5 597.5 L 327.5 27.5 L 317.5 17.5 M 327.5 27.5 L 822.5 27.5" fill="none" stroke="#36393d" stroke-miterlimit="10" transform="rotate(90,570,307.5)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 70px; margin-left: 284px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: nowrap;">FVP</div></div></div></foreignObject><text x="284" y="82" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-decoration="underline">FVP</text></switch></g><path d="M 385 55 L 745 55 L 755 65 L 755 515 L 395 515 L 385 505 L 385 55 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="rotate(90,570,285)" pointer-events="all"/><path d="M 395 515 L 395 65 L 385 55 M 395 65 L 755 65" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="rotate(90,570,285)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 115px; margin-left: 344px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: nowrap;">DUT</div></div></div></foreignObject><text x="344" y="127" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-decoration="underline">DUT</text></switch></g><path d="M 540 205 L 590 205" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 445 610 L 705 610 L 705 660 L 445 660 L 445 650 L 435 650 L 435 640 L 445 640 L 445 630 L 435 630 L 435 620 L 445 620 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 445 620 L 455 620 L 455 630 L 445 630 M 445 640 L 455 640 L 455 650 L 445 650" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="579.5" y="627.5">flash image file</text></g><rect x="680" y="470" width="60" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 485px; margin-left: 681px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">semihosting</div></div></div></foreignObject><text x="710" y="489" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">semihosting</text></switch></g><path d="M 30 245 L 120 245 L 120 295 L 30 295 L 30 285 L 20 285 L 20 275 L 30 275 L 30 265 L 20 265 L 20 255 L 30 255 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 30 255 L 40 255 L 40 265 L 30 265 M 30 275 L 40 275 L 40 285 L 30 285" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="79.5" y="262.5">Testcase</text></g><path d="M 70 245 L 70 121 L 271.89 121.15" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 277.14 121.15 L 270.14 124.65 L 271.89 121.15 L 270.14 117.65 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="90" y="90" width="60" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 105px; margin-left: 91px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">start/stop</div></div></div></foreignObject><text x="120" y="109" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">start/stop</text></switch></g><path d="M 70 295 L 70 645 L 428.63 645" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 433.88 645 L 426.88 648.5 L 428.63 645 L 426.88 641.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="150" y="180" width="110" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 195px; margin-left: 151px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">update requests to fw test API</div></div></div></foreignObject><text x="205" y="199" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">update requests to...</text></switch></g><path d="M 490 10 L 640 10 L 650 20 L 650 410 L 500 410 L 490 400 L 490 10 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" transform="rotate(90,570,210)" pointer-events="all"/><path d="M 500 410 L 500 20 L 490 10 M 500 20 L 650 20" fill="none" stroke="#82b366" stroke-miterlimit="10" transform="rotate(90,570,210)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 145px; margin-left: 374px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: nowrap;">Normal World</div></div></div></foreignObject><text x="374" y="157" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-decoration="underline">Normal World</text></switch></g><rect x="80" y="610" width="80" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 625px; margin-left: 81px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">modify/corrupt</div></div></div></foreignObject><text x="120" y="629" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">modify/corrupt</text></switch></g><path d="M 493.75 176.25 L 633.75 176.25 L 643.75 186.25 L 643.75 573.75 L 503.75 573.75 L 493.75 563.75 L 493.75 176.25 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" transform="rotate(90,568.75,375)" pointer-events="all"/><path d="M 503.75 573.75 L 503.75 186.25 L 493.75 176.25 M 503.75 186.25 L 643.75 186.25" fill="none" stroke="#6c8ebf" stroke-miterlimit="10" transform="rotate(90,568.75,375)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 315px; margin-left: 374px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: nowrap;">Secure World</div></div></div></foreignObject><text x="374" y="327" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-decoration="underline">Secure World</text></switch></g><rect x="540" y="165" width="190" height="80" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 162px; margin-left: 541px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">user<br /> process</div></div></div></foreignObject><text x="635" y="162" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">user...</text></switch></g><path d="M 600 180 L 690 180 L 690 230 L 600 230 L 600 220 L 590 220 L 590 210 L 600 210 L 600 200 L 590 200 L 590 190 L 600 190 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 600 190 L 610 190 L 610 200 L 600 200 M 600 210 L 610 210 L 610 220 L 600 220" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="649.5" y="197.5">fw_test_api</text></g><path d="M 120 270 L 170 270 L 170 215 L 583.63 215" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 588.88 215 L 581.88 218.5 L 583.63 215 L 581.88 211.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 600 355 L 690 355 L 690 405 L 600 405 L 600 395 L 590 395 L 590 385 L 600 385 L 600 375 L 590 375 L 590 365 L 600 365 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 600 365 L 610 365 L 610 375 L 600 375 M 600 385 L 610 385 L 610 395 L 600 395" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="649.5" y="372.5">Update Agent</text></g><path d="M 640 405 L 637.58 603.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 637.51 608.88 L 634.1 601.84 L 637.58 603.63 L 641.1 601.93 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 640 230 L 640 348.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 640 353.88 L 636.5 346.88 L 640 348.63 L 643.5 346.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="260" y="590" width="110" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 108px; height: 1px; padding-top: 605px; margin-left: 262px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Loaded into emulated flash on startup</div></div></div></foreignObject><text x="262" y="609" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Loaded into emulat...</text></switch></g><rect x="740" y="590" width="160" height="90" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 158px; height: 1px; padding-top: 635px; margin-left: 742px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">UEFI MBT/GPT formatted disk image with partitions for FWU metadata and firmware banks.</div></div></div></foreignObject><text x="742" y="639" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">UEFI MBT/GPT formatted dis...</text></switch></g><rect x="550" y="335" width="180" height="95" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 332px; margin-left: 551px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">secure partition</div></div></div></foreignObject><text x="640" y="332" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">secure partition</text></switch></g><path d="M 410 355 L 500 355 L 500 405 L 410 405 L 410 395 L 400 395 L 400 385 L 410 385 L 410 375 L 400 375 L 400 365 L 410 365 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 410 365 L 420 365 L 420 375 L 410 375 M 410 385 L 420 385 L 420 395 L 410 395" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="459.5" y="372.5">Bootloader</text></g><path d="M 370 490 L 540 490 L 540 540 L 370 540 L 370 530 L 360 530 L 360 520 L 370 520 L 370 510 L 360 510 L 360 500 L 370 500 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 370 500 L 380 500 L 380 510 L 370 510 M 370 520 L 380 520 L 380 530 L 370 530" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="459.5" y="507.5">Emulated NOR Flash</text></g><path d="M 450 405 L 450 483.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 450 488.88 L 446.5 481.88 L 450 483.63 L 453.5 481.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 435 625 Q 250 550 354.11 507.41" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 358.97 505.42 L 353.81 511.31 L 354.11 507.41 L 351.16 504.83 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/services/image/gpt-based-flash-layout.svg b/docs/services/image/gpt-based-flash-layout.svg
new file mode 100644
index 000000000..8f1061cda
--- /dev/null
+++ b/docs/services/image/gpt-based-flash-layout.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="401px" height="781px" viewBox="-0.5 -0.5 401 781" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2023-02-16T09:50:57.516Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;9oA7HNylA2Pn-M09WDsz&quot; version=&quot;20.3.7&quot; type=&quot;atlas&quot;&gt;&lt;mxAtlasLibraries/&gt;&lt;diagram id=&quot;MJao7NBNlqcqI8fyxszN&quot; name=&quot;Page-1&quot;&gt;7Zlbb9owGIZ/TS4tJfEB57LQwqqpHSLtql06sQNZkxgZM2C/fg6YEpZsgo0oakW4wH59iP0+/pBtHDjI1yPF5rMHyUXm+C5fO/DW8X0PQ2i+SmVjFRjgnTJVKbfaQQjTn8KKrlWXKReLo4paykyn82MxlkUhYn2kMaXk6rhaIrPjt87Z1L7RPQhhzDJRq/aScj3bqRRXan8S6XS2f7Pn2pKc7StbYTFjXK4qErxz4EBJqXepfD0QWene3pddu+EfSt8GpkShT2kA5UA9jb49DvjjZC7zBz9ffAe2lx8sW9oJj5XUxsj0hzD6Q39iB683e0eUXBZclJ26DuyvZqkW4ZzFZenKLAKjzXSemZxnkkmaZQOZSbVtCxMaizg2+kIr+SoqJRHFCJcd1qe1H6NQWqwrkp3mSMhcaLUxVWwpoNbyzW/51YEg2nOaVehBqzG7aKZvXR98NQlr7Rk2+w02pznbDno0frqsx7j8NHlMtk/ZQha6ou+elrzHJ3pP2vIe/sX74ctzucqFZpxp5vgkM6PpR8qkpmVqzJROdSoLU+tpMy9DYvR8f+vAG1OD5SWIIlqUX5T1GEXMBRTSHkBuQgCLkAcYjQKGGXG5Dy+LOUn85lDiJCKYtIPT65omqtE01t3cjMEwVfnKTPV/IPoIezEnAgRuIgCKPAyixHMBI0EUC58jRMlFIXIsKEdNEKkfQdISxF7XEHENoneFeG4kwq4pksZQDAeXwUgCzxjLIPB7JUbPRSBinIMehkHsuixw9zvJ940x6BpjrzEYrxjPwuh3vs2hjdE4CcOLYIwDRJmHCcA0jgCKIQURcgkQxI3MRsQvff8AGGHn+5ugMRqvGM/D2PkOZ7+OKhyf74b34CtTKYsysbisy0zQpPEsQGIqoqQdl9GpOxDcmsv164svocl/FqooL6Lev8Wn3ly0Z3H9+Dwpr6zM2Tn8AAbj7tdw/UTbZ/Hrcn69nvgHnKfGS3s//PWz7RvOj33TR1B73pvs4aJ8W1b5vwHe/QI=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><rect x="0" y="0" width="400" height="30" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 15px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Protective MBR</div></div></div></foreignObject><text x="200" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Protective MBR</text></switch></g><rect x="0" y="30" width="400" height="60" fill="#f5f5f5" stroke="#666666" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 60px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333333; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Primary GPT</div></div></div></foreignObject><text x="200" y="64" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Primary GPT</text></switch></g><rect x="0" y="90" width="400" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 120px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Primary FWU Metadata<br />Partition Type GUID: 8a7a84a0-8387-40f6-ab41-a8b9a5a60d23</div></div></div></foreignObject><text x="200" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Primary FWU Metadata...</text></switch></g><rect x="0" y="150" width="400" height="60" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 180px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">0:AP-Firmware<br />Partition Type GUID: 2451cd6e-90fe-4b15-bf10-a69bce2d4486</div></div></div></foreignObject><text x="200" y="184" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">0:AP-Firmware...</text></switch></g><rect x="0" y="210" width="400" height="60" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 240px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">1:AP-Firmware<br />Partition Type GUID: 2451cd6e-90fe-4b15-bf10-a69bce2d4486</div></div></div></foreignObject><text x="200" y="244" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">1:AP-Firmware...</text></switch></g><rect x="0" y="270" width="400" height="60" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 300px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">0:SCP-Firmware<br />Partition Type GUID: 691d5ea3-27fe-4104-badd-7539c00a9095</div></div></div></foreignObject><text x="200" y="304" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">0:SCP-Firmware...</text></switch></g><rect x="0" y="330" width="400" height="60" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 360px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">1:SCP-Firmware<br />Partition Type GUID: 691d5ea3-27fe-4104-badd-7539c00a9095</div></div></div></foreignObject><text x="200" y="364" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">1:SCP-Firmware...</text></switch></g><rect x="0" y="390" width="400" height="60" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 420px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">0:RSS-Firmware<br />Partition Type GUID: c948a156-58cb-4c38-b406-e60bff2223d5</div></div></div></foreignObject><text x="200" y="424" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">0:RSS-Firmware...</text></switch></g><rect x="0" y="450" width="400" height="60" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 480px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">1:RSS-Firmware<br />Partition Type GUID: c948a156-58cb-4c38-b406-e60bff2223d5</div></div></div></foreignObject><text x="200" y="484" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">1:RSS-Firmware...</text></switch></g><rect x="0" y="510" width="400" height="50" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 535px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">UEFI-Variables</div></div></div></foreignObject><text x="200" y="539" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">UEFI-Variables</text></switch></g><rect x="0" y="560" width="400" height="50" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 585px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">OS Kernel</div></div></div></foreignObject><text x="200" y="589" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">OS Kernel</text></switch></g><rect x="0" y="610" width="400" height="50" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 635px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Root FS</div></div></div></foreignObject><text x="200" y="639" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Root FS</text></switch></g><rect x="0" y="660" width="400" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 690px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Backup FWU Metadata<br />Partition Type GUID: 8a7a84a0-8387-40f6-ab41-a8b9a5a60d23</div></div></div></foreignObject><text x="200" y="694" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Backup FWU Metadata...</text></switch></g><rect x="0" y="720" width="400" height="60" fill="#f5f5f5" stroke="#666666" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 750px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333333; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Backup GPT</div></div></div></foreignObject><text x="200" y="754" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Backup GPT</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/services/image/smm-gateway-layers.svg b/docs/services/image/smm-gateway-layers.svg
new file mode 100644
index 000000000..560d4cc85
--- /dev/null
+++ b/docs/services/image/smm-gateway-layers.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than draw.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1332px" height="808px" viewBox="-0.5 -0.5 1332 808" content="&lt;mxfile host=&quot;Electron&quot; modified=&quot;2024-01-23T11:39:54.294Z&quot; agent=&quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.8 Chrome/114.0.5735.289 Electron/25.5.0 Safari/537.36&quot; etag=&quot;u70D3RMK-v4m9EBbCB7W&quot; version=&quot;21.6.8&quot; type=&quot;device&quot;&gt;&#10; &lt;diagram id=&quot;f5pL-_Ve34yj-hPsbddT&quot; name=&quot;Page-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;4154&quot; dy=&quot;2302&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;0&quot; pageScale=&quot;1&quot; pageWidth=&quot;850&quot; pageHeight=&quot;1100&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-15&quot; value=&quot;&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillStyle=auto;gradientColor=none;dashed=1;dashPattern=1 4;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;490&quot; y=&quot;120&quot; width=&quot;290&quot; height=&quot;390&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-1&quot; value=&quot;Client Processing Environment&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;strokeColor=#432D57;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;fontColor=#000000;strokeWidth=3;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;-550&quot; y=&quot;-40&quot; width=&quot;250&quot; height=&quot;300&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-2&quot; value=&quot;smm_gateway SP&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;strokeColor=#B20000;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;fontColor=#000000;strokeWidth=3;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;-120&quot; y=&quot;-40&quot; width=&quot;450&quot; height=&quot;300&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-3&quot; value=&quot;RPC Caller&amp;lt;br&amp;gt;(MM_COMMUNICATE)&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;-530&quot; y=&quot;80&quot; width=&quot;210&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-4&quot; value=&quot;Messaging Layer&amp;lt;br&amp;gt;(FFA)&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;-530&quot; y=&quot;140&quot; width=&quot;210&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-5&quot; value=&quot;RPC Endpoint&amp;lt;br&amp;gt;(MM_COMMUNICATE)&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;-100&quot; y=&quot;80&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-6&quot; value=&quot;Messaging Layer&amp;lt;br&amp;gt;(FFA)&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;-100&quot; y=&quot;140&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-7&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=3;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-3&quot; target=&quot;jY7OZYZA7oGKIM1ab5E1-5&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;-490&quot; y=&quot;270&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;-440&quot; y=&quot;220&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-8&quot; value=&quot;MM COMMUNICATE&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;jY7OZYZA7oGKIM1ab5E1-7&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;16&quot; y=&quot;-10&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-9&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=3;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-4&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;-200&quot; y=&quot;169.5&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;-100&quot; y=&quot;170&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-10&quot; value=&quot;FFA Messaging&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;jY7OZYZA7oGKIM1ab5E1-9&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;16&quot; y=&quot;-10&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-11&quot; value=&quot;Service Client&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;-530&quot; y=&quot;20&quot; width=&quot;210&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-12&quot; value=&quot;smm_variable service provider&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;-100&quot; y=&quot;20&quot; width=&quot;410&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-13&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=3;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-11&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;-260&quot; y=&quot;50&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;-100&quot; y=&quot;50&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-14&quot; value=&quot;SMM_VARIABLE_PROTOCOL&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;jY7OZYZA7oGKIM1ab5E1-13&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;27&quot; y=&quot;-10&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-15&quot; value=&quot;RPC Caller&amp;lt;br&amp;gt;(TS RPC)&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;120&quot; y=&quot;80&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-16&quot; value=&quot;Messaging Layer&amp;lt;br&amp;gt;(FFA)&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;120&quot; y=&quot;140&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-2&quot; value=&quot;&quot; style=&quot;group&quot; parent=&quot;1&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;320&quot; y=&quot;-280&quot; width=&quot;380&quot; height=&quot;300&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-1&quot; value=&quot;&quot; style=&quot;group&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-2&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;200&quot; width=&quot;230&quot; height=&quot;300&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-17&quot; value=&quot;secure storage SP&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;strokeColor=#B20000;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;fontColor=#000000;strokeWidth=3;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;230&quot; height=&quot;300&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-18&quot; value=&quot;RPC Endpoint&amp;lt;br&amp;gt;TS RPC&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;20&quot; y=&quot;120&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-19&quot; value=&quot;Messaging Layer&amp;lt;br&amp;gt;(FFA)&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;20&quot; y=&quot;180&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-20&quot; value=&quot;secure storage service provider&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;20&quot; y=&quot;60&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-21&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#d5e8d4;strokeColor=#82b366;edgeStyle=orthogonalEdgeStyle;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-16&quot; target=&quot;jY7OZYZA7oGKIM1ab5E1-19&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;-60&quot; y=&quot;209.5&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;160&quot; y=&quot;209.5&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;360&quot; y=&quot;170&quot; /&gt;&#10; &lt;mxPoint x=&quot;360&quot; y=&quot;-70&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-22&quot; value=&quot;FFA Messaging&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;jY7OZYZA7oGKIM1ab5E1-21&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;110&quot; y=&quot;-129&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-25&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#f8cecc;strokeColor=#b85450;edgeStyle=orthogonalEdgeStyle;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-12&quot; target=&quot;jY7OZYZA7oGKIM1ab5E1-20&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;40&quot; y=&quot;430&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;210&quot; y=&quot;430&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;420&quot; y=&quot;50&quot; /&gt;&#10; &lt;mxPoint x=&quot;420&quot; y=&quot;-190&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-26&quot; value=&quot;PSA Secure Storage&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;jY7OZYZA7oGKIM1ab5E1-25&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;40&quot; y=&quot;-189&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-23&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#dae8fc;strokeColor=#6c8ebf;edgeStyle=orthogonalEdgeStyle;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-15&quot; target=&quot;jY7OZYZA7oGKIM1ab5E1-18&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;400&quot; y=&quot;19.5&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;570&quot; y=&quot;19.5&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;390&quot; y=&quot;110&quot; /&gt;&#10; &lt;mxPoint x=&quot;390&quot; y=&quot;-130&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;jY7OZYZA7oGKIM1ab5E1-24&quot; value=&quot;TS RPC&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;jY7OZYZA7oGKIM1ab5E1-23&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;80&quot; y=&quot;-164&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-4&quot; value=&quot;&quot; style=&quot;group&quot; parent=&quot;1&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;520&quot; y=&quot;180&quot; width=&quot;230&quot; height=&quot;300&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-5&quot; value=&quot;crypto SP&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;strokeColor=#B20000;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;fontColor=#000000;strokeWidth=3;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-4&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;230&quot; height=&quot;300&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-6&quot; value=&quot;RPC Endpoint&amp;lt;br&amp;gt;TS RPC&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-4&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;20&quot; y=&quot;120&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-7&quot; value=&quot;Messaging Layer&amp;lt;br&amp;gt;(FFA)&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-4&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;20&quot; y=&quot;180&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-8&quot; value=&quot;crypto service provider&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-4&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;20&quot; y=&quot;60&quot; width=&quot;190&quot; height=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-9&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#f8cecc;strokeColor=#b85450;edgeStyle=orthogonalEdgeStyle;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-12&quot; target=&quot;fTWElzHCAZxmjjW7fUlU-8&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;260&quot; y=&quot;410&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;520&quot; y=&quot;260&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;420&quot; y=&quot;50&quot; /&gt;&#10; &lt;mxPoint x=&quot;420&quot; y=&quot;270&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-10&quot; value=&quot;PSA Crypto&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-9&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;50&quot; y=&quot;141&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-11&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#dae8fc;strokeColor=#6c8ebf;edgeStyle=orthogonalEdgeStyle;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-15&quot; target=&quot;fTWElzHCAZxmjjW7fUlU-6&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;320&quot; y=&quot;420&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;580&quot; y=&quot;270&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;390&quot; y=&quot;110&quot; /&gt;&#10; &lt;mxPoint x=&quot;390&quot; y=&quot;330&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-12&quot; value=&quot;TS RPC&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-11&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;70&quot; y=&quot;111&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-13&quot; value=&quot;&quot; style=&quot;endArrow=classic;startArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#d5e8d4;strokeColor=#82b366;edgeStyle=orthogonalEdgeStyle;&quot; parent=&quot;1&quot; source=&quot;jY7OZYZA7oGKIM1ab5E1-16&quot; target=&quot;fTWElzHCAZxmjjW7fUlU-7&quot; edge=&quot;1&quot;&gt;&#10; &lt;mxGeometry width=&quot;50&quot; height=&quot;50&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;360&quot; y=&quot;530&quot; as=&quot;sourcePoint&quot; /&gt;&#10; &lt;mxPoint x=&quot;620&quot; y=&quot;380&quot; as=&quot;targetPoint&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;360&quot; y=&quot;170&quot; /&gt;&#10; &lt;mxPoint x=&quot;360&quot; y=&quot;390&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-14&quot; value=&quot;FFA Messaging&quot; style=&quot;text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#ffffff;&quot; parent=&quot;fTWElzHCAZxmjjW7fUlU-13&quot; vertex=&quot;1&quot; connectable=&quot;0&quot;&gt;&#10; &lt;mxGeometry x=&quot;-0.247&quot; relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint x=&quot;100&quot; y=&quot;81&quot; as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fTWElzHCAZxmjjW7fUlU-16&quot; value=&quot;If&amp;amp;nbsp;&amp;lt;b&amp;gt;UEFI_AUTH_VAR &amp;lt;/b&amp;gt;enabled&quot; style=&quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;&quot; parent=&quot;1&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry x=&quot;530&quot; y=&quot;120&quot; width=&quot;220&quot; height=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;/root&gt;&#10; &lt;/mxGraphModel&gt;&#10; &lt;/diagram&gt;&#10;&lt;/mxfile&gt;&#10;"><defs/><g><rect x="1041" y="417" width="290" height="390" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-dasharray="1 4" pointer-events="all"/><rect x="1" y="257" width="250" height="300" rx="37.5" ry="37.5" fill="#e6e6e6" stroke="#432d57" stroke-width="3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 254px; margin-left: 2px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Client Processing Environment</div></div></div></foreignObject><text x="126" y="254" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Client Processing Environment</text></switch></g><rect x="431" y="257" width="450" height="300" rx="45" ry="45" fill="#e6e6e6" stroke="#b20000" stroke-width="3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 448px; height: 1px; padding-top: 254px; margin-left: 432px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">smm_gateway SP</div></div></div></foreignObject><text x="656" y="254" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">smm_gateway SP</text></switch></g><rect x="21" y="377" width="210" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 407px; margin-left: 22px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">RPC Caller<br />(MM_COMMUNICATE)</div></div></div></foreignObject><text x="126" y="411" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">RPC Caller...</text></switch></g><rect x="21" y="437" width="210" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 467px; margin-left: 22px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Messaging Layer<br />(FFA)</div></div></div></foreignObject><text x="126" y="471" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Messaging Layer...</text></switch></g><rect x="451" y="377" width="190" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 407px; margin-left: 452px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">RPC Endpoint<br />(MM_COMMUNICATE)</div></div></div></foreignObject><text x="546" y="411" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">RPC Endpoint...</text></switch></g><rect x="451" y="437" width="190" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 467px; margin-left: 452px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Messaging Layer<br />(FFA)</div></div></div></foreignObject><text x="546" y="471" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Messaging Layer...</text></switch></g><path d="M 241.1 407 L 440.9 407" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 234.35 407 L 243.35 402.5 L 241.1 407 L 243.35 411.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><path d="M 447.65 407 L 438.65 411.5 L 440.9 407 L 438.65 402.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 398px; margin-left: 331px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">MM COMMUNICATE</div></div></div></foreignObject><text x="331" y="401" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">MM COMMUNICATE</text></switch></g><path d="M 241.1 467 L 440.9 467" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 234.35 467 L 243.35 462.5 L 241.1 467 L 243.35 471.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><path d="M 447.65 467 L 438.65 471.5 L 440.9 467 L 438.65 462.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 458px; margin-left: 331px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">FFA Messaging</div></div></div></foreignObject><text x="331" y="461" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">FFA Messaging</text></switch></g><rect x="21" y="317" width="210" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 347px; margin-left: 22px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Service Client</div></div></div></foreignObject><text x="126" y="351" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Service Client</text></switch></g><rect x="451" y="317" width="410" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 408px; height: 1px; padding-top: 347px; margin-left: 452px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">smm_variable service provider</div></div></div></foreignObject><text x="656" y="351" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">smm_variable service provider</text></switch></g><path d="M 241.1 347 L 440.9 347" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 234.35 347 L 243.35 342.5 L 241.1 347 L 243.35 351.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><path d="M 447.65 347 L 438.65 351.5 L 440.9 347 L 438.65 342.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 338px; margin-left: 342px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">SMM_VARIABLE_PROTOCOL</div></div></div></foreignObject><text x="342" y="341" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">SMM_VARIABLE_PROTOCOL</text></switch></g><rect x="671" y="377" width="190" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 407px; margin-left: 672px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">RPC Caller<br />(TS RPC)</div></div></div></foreignObject><text x="766" y="411" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">RPC Caller...</text></switch></g><rect x="671" y="437" width="190" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 467px; margin-left: 672px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Messaging Layer<br />(FFA)</div></div></div></foreignObject><text x="766" y="471" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Messaging Layer...</text></switch></g><rect x="1071" y="17" width="230" height="300" rx="34.5" ry="34.5" fill="#e6e6e6" stroke="#b20000" stroke-width="3" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 228px; height: 1px; padding-top: 14px; margin-left: 1072px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">secure storage SP</div></div></div></foreignObject><text x="1186" y="14" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">secure storage SP</text></switch></g><rect x="1091" y="137" width="190" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 167px; margin-left: 1092px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">RPC Endpoint<br />TS RPC</div></div></div></foreignObject><text x="1186" y="171" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">RPC Endpoint...</text></switch></g><rect x="1091" y="197" width="190" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 227px; margin-left: 1092px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Messaging Layer<br />(FFA)</div></div></div></foreignObject><text x="1186" y="231" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Messaging Layer...</text></switch></g><rect x="1091" y="77" width="190" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 107px; margin-left: 1092px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">secure storage service provider</div></div></div></foreignObject><text x="1186" y="111" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">secure storage service provider</text></switch></g><path d="M 871.1 467 L 901 467 Q 911 467 911 457 L 911 237 Q 911 227 921 227 L 1080.9 227" fill="none" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 864.35 467 L 873.35 462.5 L 871.1 467 L 873.35 471.5 Z" fill="#82b366" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 1087.65 227 L 1078.65 231.5 L 1080.9 227 L 1078.65 222.5 Z" fill="#82b366" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 212px; margin-left: 1022px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">FFA Messaging</div></div></div></foreignObject><text x="1022" y="215" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">FFA Messaging</text></switch></g><path d="M 871.1 347 L 961 347 Q 971 347 971 337 L 971 117 Q 971 107 981 107 L 1080.9 107" fill="none" stroke="#b85450" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 864.35 347 L 873.35 342.5 L 871.1 347 L 873.35 351.5 Z" fill="#b85450" stroke="#b85450" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 1087.65 107 L 1078.65 111.5 L 1080.9 107 L 1078.65 102.5 Z" fill="#b85450" stroke="#b85450" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 92px; margin-left: 1012px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">PSA Secure Storage</div></div></div></foreignObject><text x="1012" y="95" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PSA Secure Storage</text></switch></g><path d="M 871.1 407 L 931 407 Q 941 407 941 397 L 941 177 Q 941 167 951 167 L 1080.9 167" fill="none" stroke="#6c8ebf" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 864.35 407 L 873.35 402.5 L 871.1 407 L 873.35 411.5 Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 1087.65 167 L 1078.65 171.5 L 1080.9 167 L 1078.65 162.5 Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 147px; margin-left: 1022px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">TS RPC</div></div></div></foreignObject><text x="1022" y="150" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">TS RPC</text></switch></g><rect x="1071" y="477" width="230" height="300" rx="34.5" ry="34.5" fill="#e6e6e6" stroke="#b20000" stroke-width="3" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 228px; height: 1px; padding-top: 474px; margin-left: 1072px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">crypto SP</div></div></div></foreignObject><text x="1186" y="474" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">crypto SP</text></switch></g><rect x="1091" y="597" width="190" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 627px; margin-left: 1092px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">RPC Endpoint<br />TS RPC</div></div></div></foreignObject><text x="1186" y="631" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">RPC Endpoint...</text></switch></g><rect x="1091" y="657" width="190" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 687px; margin-left: 1092px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Messaging Layer<br />(FFA)</div></div></div></foreignObject><text x="1186" y="691" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Messaging Layer...</text></switch></g><rect x="1091" y="537" width="190" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 567px; margin-left: 1092px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">crypto service provider</div></div></div></foreignObject><text x="1186" y="571" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">crypto service provider</text></switch></g><path d="M 871.1 347 L 961 347 Q 971 347 971 357 L 971 557 Q 971 567 981 567 L 1080.9 567" fill="none" stroke="#b85450" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 864.35 347 L 873.35 342.5 L 871.1 347 L 873.35 351.5 Z" fill="#b85450" stroke="#b85450" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 1087.65 567 L 1078.65 571.5 L 1080.9 567 L 1078.65 562.5 Z" fill="#b85450" stroke="#b85450" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 548px; margin-left: 1022px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">PSA Crypto</div></div></div></foreignObject><text x="1022" y="551" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PSA Crypto</text></switch></g><path d="M 871.1 407 L 931 407 Q 941 407 941 417 L 941 617 Q 941 627 951 627 L 1080.9 627" fill="none" stroke="#6c8ebf" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 864.35 407 L 873.35 402.5 L 871.1 407 L 873.35 411.5 Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 1087.65 627 L 1078.65 631.5 L 1080.9 627 L 1078.65 622.5 Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 608px; margin-left: 1012px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">TS RPC</div></div></div></foreignObject><text x="1012" y="611" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">TS RPC</text></switch></g><path d="M 871.1 467 L 901 467 Q 911 467 911 477 L 911 677 Q 911 687 921 687 L 1080.9 687" fill="none" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 864.35 467 L 873.35 462.5 L 871.1 467 L 873.35 471.5 Z" fill="#82b366" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><path d="M 1087.65 687 L 1078.65 691.5 L 1080.9 687 L 1078.65 682.5 Z" fill="#82b366" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 668px; margin-left: 1012px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: #ffffff; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">FFA Messaging</div></div></div></foreignObject><text x="1012" y="671" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">FFA Messaging</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 432px; margin-left: 1082px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">If <b>UEFI_AUTH_VAR </b>enabled</div></div></div></foreignObject><text x="1191" y="436" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">If UEFI_AUTH_VAR enabled</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/services/image/uefi-variable-structure.svg b/docs/services/image/uefi-variable-structure.svg
new file mode 100644
index 000000000..8645968a4
--- /dev/null
+++ b/docs/services/image/uefi-variable-structure.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1951px" height="461px" viewBox="-0.5 -0.5 1951 461" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2023-11-27T13:39:12.071Z&quot; agent=&quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36&quot; etag=&quot;ZgD_82_BjbNSsNJPHEsn&quot; version=&quot;21.1.7&quot; type=&quot;atlas&quot;&gt;&lt;diagram id=&quot;HaAGp1sIpwXQiMiukq5O&quot; name=&quot;Page-1&quot;&gt;7Zxdf6I4FIc/TS/lRwhEuGy1nc5Od+elM9vdywhBs4PgYqw6n34SSRRIfOsU68vUC+EQgvyfk+TkBHoFO8PZuxyPBn9mEUmuHDuaXcHulcP/oMu/hGVeWAAIQGHp5zSStpXhkf4g0mhL64RGZFwpyLIsYXRUNYZZmpKQVWw4z7NptVicJdWrjnBfXtFeGR5DnBCt2BON2KCw+l6p9D2h/YG6MrDlkSFWhaVhPMBRNi2Z4O0V7ORZxoqt4axDEqGe0qU4727N0eUPy0nKdjnh+cNn+3b20Pn+39Pdl/+/fg6iEWi5ks8zTibyjuWvZXMlQT/PJiP9avIHPJOckZmJBe4lpH673FFINiQsn/Ny8qwW8qVE0klaQBmmK8nbbWkblOVWamOJub+sfaUE35Bi7CFMsF0XLksaEVEJuII30wFl5HGEQ3F0ylsDtw3YMJGHcUL7Kd8OuX4k5wYuEsM0Fdtdm+/rAm8GVpddl/ftxAOaeO++vedfKOGXvunlfKsvtgDipXpzRjZoa2/XNqZJ0smSLF+cC+M4dsKQ28csz76T0pEI9ZCHDiK+6gGrng11vwaOAQ1qioyjkelihhfdrkbHP3c4wD0yOlCj8xcekguls5T5WOjoQ+U1YzntTRgPUC6PD/SPjI9nbD06Gf6Nh0Lnhb3UwgqrLHPe8Dz7yOAh48C0DV5p8GoYXoSJHxvhodAnvfiQ8NCxRRWu3vQ08RufRbiwqkoL6LL46KBxsKt79RpdNH/rXt/6d52N/tbPcUS5kOpYmqW8zpvqtOSlTun9Mpc3lL29Xfa9Jm/LqbtQsJ/g8Vhu16CFIfHi2AQNIhjAqAEeR6W7r+n+lfLRlYm++fQnf7sjUEdr3TSyuBuUPrv12p5reW7p4zVFT095RNMHkvb5rzv56HZ/dvCk4Kl8ZAne9At5pmOapRdIz/FOi56eMJt2+M3SmIaYka/z0RkkAPaGCNunBVHPrQmGZnjnP/i5wWnR03Nvgl4xCT1TROi0AhRPT8B9wvMkw9HrEvJDYibU8/nd2Yck1D6xKETPA3y7vXvPLX/jnC5mjHVSXAhWm2xVZJeT2jIjadJW1ISsfLxMruWBIY0icRkj/6qHHA6oY8jVuAZkTtvihUsf2BAzpMceGqTGczdAeY56TKBtkMmGptksaGw2u4MwjWQRmuuA0DpiG7MIhxYe6P38I2/RFjedRzC1B4blMrIVQLv01640F1dvLSiwVKGDpICB3vUraA90zPiXeRnTPXd0tTDYgCowtK7mOOkpacXpnuCI63GxpIC/FdUyd3oYVnoeW7G6UETOdkSmlHdzhPSMd701bV7AXNf2TnYpen+m0N3e7EwRcnNQ9US4wvRxmpqYnn8A4tYaHjJAgsBSo0uZk9sUJ6gH6IrTLs8O1LrSC2pxCAhSq2ASbEfrW757QLRqlqwnEgQ1zCY5WQaWR5dQ+IVl9/1Z+ghZQRu1XRf4yHaRISPkQct2oON5PoCBBz0DSNgUSM8cwiiC4GzbWL3DNIxqjumhbKcxEutDlYsd1dre8Y1q3vro4/eotrEn9I99VEP6qFbuDM0gK9kTu1V0mlWuZwq03jrfvAtFjsZPH8DGAzwSm3FCZtfiBTQuEUkjudkNRd6XhlUIVWL7P3mqFIFOcTH5Gh2yfE/Ux4FJCxAAE9wjyQ0Ov/cX161FQTpOdY/ZJA/JBnnUY3cM532y0RWKciTqk41+UALtGTgrW04SzOhzlYgJvrzCp4ymrBQNV71sufSgaijuW5608iCtHlBbTQV1Pyx00SpauOLyrn/BO/UVbNuy0uYddIf1Cu5L+fwfcbrlqd1/Zd2Lne5M1l3szVXnJT3ARTXHRm2DY4t9dfWIxHiy6Egbc3f1Ouo2d1cB95H4O6w7fD2RsqvD1ysKdvN37mh4Xio2EgXGe/ze6nuufKOo8aWNKbgL06ePNv1jSlvBbPz0YwKHhvfk1rajcJIn85ucO5jwgm3jbXWaGCd0dC+3F376KRtTJp7Zg928IL+chT7Uji9no2rempC4XF6bta519T1mNbVHsoxv6ppWC516r/qSQdlISu/1fpMSWrk7kDKlVd3XyKsaSa19OOR5y8MhuyZwymHtamhwXLUvKwabpNeSQK/AwqtFBi3kaSiWeF57JmJEoS8CShQfiPjdjyxbzEjOHUyw/RVG4+rsC7jw3dW/eihGqdV/zIC3PwE=&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="0" y="0" width="770" height="100" rx="15" ry="15" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><rect x="20" y="30" width="120" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 60px; margin-left: 21px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">GUID<br />16 byte</div></div></div></foreignObject><text x="80" y="64" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">GUID...</text></switch></g><rect x="140" y="30" width="120" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 60px; margin-left: 141px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">DataSize<br />8 byte</div></div></div></foreignObject><text x="200" y="64" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">DataSize...</text></switch></g><rect x="260" y="30" width="120" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 60px; margin-left: 261px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">NameSize<br />8 byte</div></div></div></foreignObject><text x="320" y="64" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">NameSize...</text></switch></g><rect x="380" y="30" width="120" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 60px; margin-left: 381px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Attributes<br />8 byte</div></div></div></foreignObject><text x="440" y="64" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Attributes...</text></switch></g><rect x="500" y="30" width="120" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 60px; margin-left: 501px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Name<br />&lt;NameSize&gt; byte</div></div></div></foreignObject><text x="560" y="64" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Name...</text></switch></g><rect x="620" y="30" width="120" height="60" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 60px; margin-left: 621px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Data<br />&lt;DataSize&gt; byte</div></div></div></foreignObject><text x="680" y="64" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Data...</text></switch></g><rect x="250" y="170" width="860" height="100" rx="15" ry="15" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><rect x="250" y="170" width="860" height="100" rx="15" ry="15" fill="#cce5ff" stroke="#36393d" pointer-events="none"/><rect x="260" y="206.36" width="120" height="54.55" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 234px; margin-left: 261px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">TimeStamp<br />16 byte</div></div></div></foreignObject><text x="320" y="237" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">TimeStamp...</text></switch></g><rect x="380" y="206.36" width="120" height="54.55" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 234px; margin-left: 381px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">dwLength<br />8 byte</div></div></div></foreignObject><text x="440" y="237" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">dwLength...</text></switch></g><rect x="500" y="206.36" width="120" height="54.55" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 234px; margin-left: 501px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">wRevision<br />8 byte</div></div></div></foreignObject><text x="560" y="237" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">wRevision...</text></switch></g><rect x="620" y="206.36" width="120" height="54.55" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 234px; margin-left: 621px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">wCertificateType<br />8 byte</div></div></div></foreignObject><text x="680" y="237" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">wCertificateType...</text></switch></g><rect x="740" y="206.36" width="120" height="54.55" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 234px; margin-left: 741px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">CertType<br />16 byte</div></div></div></foreignObject><text x="800" y="237" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">CertType...</text></switch></g><rect x="860" y="206.36" width="120" height="54.55" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 234px; margin-left: 861px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">CertData</div></div></div></foreignObject><text x="920" y="237" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">CertData</text></switch></g><rect x="980" y="206.36" width="120" height="54.55" fill="#f8cecc" stroke="#b85450" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 234px; margin-left: 981px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Payload</div></div></div></foreignObject><text x="1040" y="237" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Payload</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 184px; margin-left: 971px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">UEFI Variable</div></div></div></foreignObject><text x="1040" y="187" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">UEFI Variable</text></switch></g><rect x="525" y="350" width="1030" height="110" rx="16.5" ry="16.5" fill="#f8cecc" stroke="#b85450" pointer-events="none"/><rect x="545.93" y="390" width="69.07" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 67px; height: 1px; padding-top: 420px; margin-left: 547px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. Type<br />16 byte</div></div></div></foreignObject><text x="580" y="424" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. Type...</text></switch></g><rect x="615" y="390" width="90" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 420px; margin-left: 616px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. List Size<br />4 byte</div></div></div></foreignObject><text x="660" y="424" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. List Size...</text></switch></g><rect x="705" y="390" width="100" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 420px; margin-left: 706px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. Header Size<br />4 byte</div></div></div></foreignObject><text x="755" y="424" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. Header Siz...</text></switch></g><rect x="805" y="390" width="60" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 420px; margin-left: 806px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. Size<br />4 byte</div></div></div></foreignObject><text x="835" y="424" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. Size...</text></switch></g><rect x="865" y="390" width="140" height="60" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 420px; margin-left: 866px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. Header<br />&lt;Sign. Header Size&gt; byte</div></div></div></foreignObject><text x="935" y="424" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. Header...</text></switch></g><rect x="1005" y="410" width="131.16" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 129px; height: 1px; padding-top: 430px; margin-left: 1006px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. Owner<br />16 byte</div></div></div></foreignObject><text x="1071" y="434" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. Owner...</text></switch></g><rect x="1136.16" y="410" width="138.84" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 137px; height: 1px; padding-top: 430px; margin-left: 1137px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. Data<br />&lt;Sign. Size&gt; byte</div></div></div></foreignObject><text x="1206" y="434" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. Data...</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 151px; height: 1px; padding-top: 365px; margin-left: 1393px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">UEFI Signature List</div></div></div></foreignObject><text x="1468" y="369" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">UEFI Signature List</text></switch></g><rect x="1005" y="390" width="270" height="20" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 268px; height: 1px; padding-top: 400px; margin-left: 1006px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Signature 1</div></div></div></foreignObject><text x="1140" y="404" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Signature 1</text></switch></g><rect x="1275" y="410" width="131.16" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 129px; height: 1px; padding-top: 430px; margin-left: 1276px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. Owner<br />16 byte</div></div></div></foreignObject><text x="1341" y="434" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. Owner...</text></switch></g><rect x="1406.16" y="410" width="138.84" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 137px; height: 1px; padding-top: 430px; margin-left: 1407px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Sign. Data<br />&lt;Sign. Size&gt; byte</div></div></div></foreignObject><text x="1476" y="434" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sign. Data...</text></switch></g><rect x="1275" y="390" width="270" height="20" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 268px; height: 1px; padding-top: 400px; margin-left: 1276px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Signature &lt;Sign. List Size - 1&gt;</div></div></div></foreignObject><text x="1410" y="404" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Signature &lt;Sign. List Size - 1&gt;</text></switch></g><path d="M 696 169.5 L 664 169.5 L 664 112.05 L 653.5 112.05 L 680 90.5 L 706.5 112.05 L 696 112.05 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 130px; margin-left: 680px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: nowrap;">1</div></div></div></foreignObject><text x="680" y="135" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px" text-anchor="middle">1</text></switch></g><path d="M 1063 349.5 L 1017 349.5 L 1017 300 L 1017 282.42 L 1006.5 282.42 L 1040 261.41 L 1073.5 282.42 L 1063 282.42 L 1063 300 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="1.42" pointer-events="none"/><path d="M 1017 282.42 L 1006.5 282.42 L 1040 261.41 L 1073.5 282.42 L 1063 282.42" fill="none" stroke="#b85450" stroke-miterlimit="4" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 305px; margin-left: 1040px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: nowrap;">0..n</div></div></div></foreignObject><text x="1040" y="310" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px" text-anchor="middle">0..n</text></switch></g><path d="M 1180 0 L 1172.5 0 Q 1165 0 1165 10 L 1165 125 Q 1165 135 1157.5 135 L 1153.75 135 Q 1150 135 1157.5 135 L 1161.25 135 Q 1165 135 1165 145 L 1165 260 Q 1165 270 1172.5 270 L 1180 270" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="translate(1165,0)scale(-1,1)translate(-1165,0)" pointer-events="none"/><path d="M 1660 0 L 1650 0 Q 1640 0 1640 10 L 1640 220 Q 1640 230 1630 230 L 1625 230 Q 1620 230 1630 230 L 1635 230 Q 1640 230 1640 240 L 1640 450 Q 1640 460 1650 460 L 1660 460" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="translate(1640,0)scale(-1,1)translate(-1640,0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 135px; margin-left: 1280px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 24px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; font-weight: bold; white-space: nowrap;">UEFI variable</div></div></div></foreignObject><text x="1280" y="142" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="24px" text-anchor="middle" font-weight="bold">UEFI variable</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 230px; margin-left: 1805px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 24px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; font-weight: bold; white-space: nowrap;">UEFI Key Store variable</div></div></div></foreignObject><text x="1805" y="237" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="24px" text-anchor="middle" font-weight="bold">UEFI Key Store variable</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/services/image/update-agent-components.svg b/docs/services/image/update-agent-components.svg
new file mode 100644
index 000000000..526c3ad5d
--- /dev/null
+++ b/docs/services/image/update-agent-components.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="834px" height="501px" viewBox="-0.5 -0.5 834 501" content="&lt;mxfile host=&quot;confluence.arm.com&quot; modified=&quot;2023-02-16T09:32:33.504Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;OKKkJQnMIhDDIoBytUQw&quot; version=&quot;20.3.7&quot; type=&quot;atlas&quot;&gt;&lt;mxAtlasLibraries/&gt;&lt;diagram id=&quot;afqreZy9bPJOplJgL8vq&quot; name=&quot;Page-1&quot;&gt;5Ztdk6I4FIZ/jZduARG1L1udnZ2qnq2usqZm56orDUFTE4kb4kfvr98ACWiCvegAZmlvhJPkQN48OSQHHYD55viZwe36Kw0RGXhOeByAxcDzXB8A8ZVa3qQFPPi5ZcVwKG2lYYn/QdLoSOsOhyg5q8gpJRxvz40BjWMU8DMbZIwezqtFlJxfdQtX8opOaVgGkCCj2ncc8nVunfontf9AeLVWV3YdWbKBqrI0JGsY0sOJCXwagDmjlOdHm+MckVQ9pUve7vcLpcWNMRTzOg3Qt+/L5Rc++ca28OnP5WL3FQZDNT57SHayxwNvTITDWYj36V3zNynF+O9deqszjo58CAlexQPwKGoQFKXmsoI4WqXfS8T2OEDK3ytTBV9ijlgEq4qURXQju76yeme34jG6i0OUdswRxYc15mi5TR2CxUGAKGxrviHizBWHESZkTgllWVuA3NBHE2FPOKM/kSqJaSyazwh8ReSZJphjKjq4kL3bI8axoOJJK97gMExvaiYFWbCchaLBo7QXFRNxnzhePWV+s9s3B1KObeoDHU9McmA/I7pBnL2JKrJ06Cns5DwbjuX5oYR2omzrE2AfpA3KebIqfJcoiQNJ0zVkOe2RNaesgp053WzFIMY86YCiEKJpFPScIr8mRN64LYq8h/YoUo6ElnGlp1cY/FxlkAyDfHxTfzgWwwZJpctnAnlE2eYEwNz7+9HN3g7NaRzh1Y7BjNTretXgbIuiyAvuN9vamFsA1JxcrtvW5HKNuRUddi9bRvdizcUaHUDH8R0UpXYa8/OBFR9jYLMW7mI2b0b8qfZwHJnSu16F9O2FNUP53TaEHL2I5aToZW+Vr1iVdCu8udyNDi8Jz9YTfRXdvTvuI0N1HCccEoLYCxYiH3skfrHylup7d1ffN9TfU7LboN5JX2y1rZF+XBVuQsxQIELOW4+kH9oW6CeXQ06jskcOBA40ZXeyT5Xss8UkL2lCdtfXVpUVyE+71H36MXTXZa/YKXcqu7lN7qPstsGudmbGo7VRzcfhdDIeXRPZwaM/Am4zmlsXYVxz29o70Q3SK56n3Ypu7lh7JzqwTnRzt9o70UfWhRdzs2rIjeLwMX23KM4CApMEB+cKnw8HOmL+V3r8my/Pfsh66fHieFJt8aZOYtGXk0bp6Y/TsrJZdqbaXRyRhO5YgN7rd16PQ7ZC/J16Ug0UqvemF8b3ZPz8ivFTNoYI5Hh//ra1alDlFZ4pThNkxdNpemHOKhd5v2WrEg3DkQc0R3rWNRfGcJQxVnT7F7Azd+lNYXcCXYlgNXa34+PVxGdsFT56yNffhtalR/fjgo7pMRMNHyJo1aUOWEXdSMtTFZmRa7EzHOnRr23szCzLr2J3I0Ilrl59Xm/nDtTkbmQVd8WLAJUfdf6v3JlZpsbC3cTmeFeXO98q7sCDhsvo1ses7mjaMXdVv0ZpiLsr4lb33I1qcjexirvRpRehV8c73VHH3Klwe//n7EWE/hONqR1oqO3drY++8eTOKJjZT9tQaCyaPNiBjBz5iRYECr/XImQ40nedbSPkfdCnmF+TO5X6sQU8/Rclt24XDUcdL9u9qj8bfIAsRW3uXLu4036x6t6aHdMdeR1nx7wWU/pWbxdrg+dZDd7NeQrDkb4BaBu81pL6bh+osysr6+vZsVvXd4ajxtZ34rT8v2BevfzbJfj0Lw==&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><rect x="73" y="0" width="760" height="90" fill="#e1d5e7" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 762px; height: 1px; padding-top: 45px; margin-left: -691px;"><div style="box-sizing: border-box; font-size: 0px; text-align: right;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div style="text-align: left;">Service<br />Interface<br /></div></div></div></div></foreignObject><text x="71" y="49" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">Service...</text></switch></g><rect x="73" y="110" width="760" height="260" fill="#dae8fc" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 762px; height: 1px; padding-top: 240px; margin-left: -691px;"><div style="box-sizing: border-box; font-size: 0px; text-align: right;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div style="text-align: left;">Core<br />Components</div></div></div></div></foreignObject><text x="71" y="244" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">Core...</text></switch></g><rect x="73" y="390" width="760" height="110" fill="#fff2cc" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 762px; height: 1px; padding-top: 445px; margin-left: -691px;"><div style="box-sizing: border-box; font-size: 0px; text-align: right;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div style="text-align: left;"><span style="background-color: initial;">Platform</span></div><div style="text-align: left;"><span style="background-color: initial;">Configuration</span></div></div></div></div></foreignObject><text x="71" y="449" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">Platform...</text></switch></g><rect x="353" y="20" width="120" height="60" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 354px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">fwu_provider</div></div></div></foreignObject><text x="413" y="54" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">fwu_provider</text></switch></g><rect x="353" y="120" width="120" height="60" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 150px; margin-left: 354px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">update_agent</div></div></div></foreignObject><text x="413" y="154" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">update_agent</text></switch></g><rect x="353" y="200" width="120" height="60" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 230px; margin-left: 354px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">fw_store</div></div></div></foreignObject><text x="413" y="234" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">fw_store</text></switch></g><rect x="213" y="300" width="120" height="60" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 330px; margin-left: 214px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">installer_index</div></div></div></foreignObject><text x="273" y="334" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">installer_index</text></switch></g><rect x="493" y="300" width="120" height="60" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 330px; margin-left: 494px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">volume_index</div></div></div></foreignObject><text x="553" y="334" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">volume_index</text></switch></g><rect x="193" y="120" width="120" height="60" fill="#0050ef" stroke="#001dbc" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 150px; margin-left: 194px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">fw_directory</div></div></div></foreignObject><text x="253" y="154" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">fw_directory</text></switch></g><rect x="123" y="400" width="80" height="60" fill="#f0a30a" stroke="#bd7000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 430px; margin-left: 124px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">installer</div></div></div></foreignObject><text x="163" y="434" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">installer</text></switch></g><rect x="223" y="410" width="80" height="60" fill="#f0a30a" stroke="#bd7000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 440px; margin-left: 224px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">installer</div></div></div></foreignObject><text x="263" y="444" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">installer</text></switch></g><rect x="323" y="400" width="80" height="60" fill="#f0a30a" stroke="#bd7000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 430px; margin-left: 324px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">installer</div></div></div></foreignObject><text x="363" y="434" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">installer</text></switch></g><rect x="423" y="400" width="80" height="60" fill="#6d8764" stroke="#3a5431" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 430px; margin-left: 424px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">volume</div></div></div></foreignObject><text x="463" y="434" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">volume</text></switch></g><rect x="523" y="420" width="80" height="60" fill="#6d8764" stroke="#3a5431" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 450px; margin-left: 524px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">volume</div></div></div></foreignObject><text x="563" y="454" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">volume</text></switch></g><rect x="623" y="420" width="80" height="60" fill="#6d8764" stroke="#3a5431" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 450px; margin-left: 624px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">volume</div></div></div></foreignObject><text x="663" y="454" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">volume</text></switch></g><rect x="723" y="400" width="80" height="60" fill="#6d8764" stroke="#3a5431" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 430px; margin-left: 724px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #ffffff; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(255, 255, 255); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">volume</div></div></div></foreignObject><text x="763" y="434" fill="#ffffff" font-family="Helvetica" font-size="12px" text-anchor="middle">volume</text></switch></g><path d="M 413 80 L 413 113.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 413 118.88 L 409.5 111.88 L 413 113.63 L 416.5 111.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 353 150 L 319.37 150" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 314.12 150 L 321.12 146.5 L 319.37 150 L 321.12 153.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 413 180 L 413 193.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 413 198.88 L 409.5 191.88 L 413 193.63 L 416.5 191.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 383 260 L 278.98 297.82" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 274.05 299.62 L 279.43 293.94 L 278.98 297.82 L 281.83 300.52 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 443 260 L 547.02 297.82" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 551.95 299.62 L 544.17 300.52 L 547.02 297.82 L 546.57 293.94 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 243 360 L 168.7 397.15" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 164 399.5 L 168.7 393.24 L 168.7 397.15 L 171.83 399.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 273 360 L 264.25 403.76" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 263.22 408.9 L 261.16 401.35 L 264.25 403.76 L 268.02 402.73 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 311.57 360 L 357.97 396.09" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 362.12 399.31 L 354.44 397.78 L 357.97 396.09 L 358.74 392.25 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 523 360 L 468.3 396.47" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 463.93 399.38 L 467.81 392.58 L 468.3 396.47 L 471.7 398.41 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 553 360 L 561.95 413.72" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 562.82 418.9 L 558.21 412.57 L 561.95 413.72 L 565.12 411.42 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 583 360 L 657.91 416.18" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 662.11 419.33 L 654.41 417.93 L 657.91 416.18 L 658.61 412.33 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 613 360 L 756.85 398.36" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 761.92 399.71 L 754.25 401.29 L 756.85 398.36 L 756.06 394.53 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/docs/developer/service-descriptions/index.rst b/docs/services/index.rst
index 5962e3709..52379f61e 100644
--- a/docs/developer/service-descriptions/index.rst
+++ b/docs/services/index.rst
@@ -1,5 +1,5 @@
-Service Descriptions
-====================
+Services
+========
.. toctree::
:maxdepth: 1
@@ -7,10 +7,13 @@ Service Descriptions
attest-service-description
crypto-service-description
+ fwu/index
secure-storage-service-description
+ block-storage-service-description
+ uefi-smm-services
--------------
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/service-descriptions/secure-storage-service-description.rst b/docs/services/secure-storage-service-description.rst
index defb2b5af..f786af575 100644
--- a/docs/developer/service-descriptions/secure-storage-service-description.rst
+++ b/docs/services/secure-storage-service-description.rst
@@ -1,7 +1,7 @@
-Secure Storage Service Description
-==================================
-Service Overview
-----------------
+Secure Storage Service
+======================
+Overview
+--------
The Secure Storage service provides a generic persistent object store for valuable
assets such as cryptographic keys. The confidentiality and integrity of stored data
is typically achieved using keys that are bound to the device. The backend object
@@ -150,7 +150,7 @@ Persistent Key Store for Crypto Service Provider
''''''''''''''''''''''''''''''''''''''''''''''''
The Crypto service provider uses the Mbed Crypto portion of Mbed TLS to implement crypto
operations. Persistent keys are stored via the PSA Internal Trusted Storage C API.
-In the opteesp deployment of the Crypto service provider, a storage client backend is
+In the opteesp and sp deployments of the Crypto service provider, a storage client backend is
used that accesses a secure store provided by a separate secure partition. The following
deployment diagram illustrates the storage frontend/backend combination used:
@@ -167,6 +167,6 @@ access is brokered by an S-EL0 proxy:
--------------
-*Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/services/uefi-smm-services.rst b/docs/services/uefi-smm-services.rst
new file mode 100644
index 000000000..b2c8a7bb1
--- /dev/null
+++ b/docs/services/uefi-smm-services.rst
@@ -0,0 +1,431 @@
+UEFI SMM Services
+=================
+The Trusted Services project provides support for UEFI System Management Mode (SMM) services via the
+SMM Gateway secure partition. The SMM Gateway adopts the API Gateway design pattern, popular in
+microservices architecture. The pattern decouples clients from backend service providers using an
+API gateway that presents a domain specific interface to clients while delegating operations to a
+set of backend microservices. An API gateway will typically use multiple backend services and may
+perform protocol translation while presenting a single service entry point for clients. The SMM
+Gateway works in a similar manner - clients access SMM services using standard SMM protocol messages,
+carried by an RPC mechanism. Service requests are forwarded by the SMM Gateway to backend service
+providers for operations such as secure persistent storage and signature verification.
+
+SMM Gateway is intended to be used on non-EDK2 platforms as an alternative to the EDK2 StandaloneMM
+(StMM) component. The current SMM Gateway version only supports the SMM Variable service. Additional
+SMM service providers may be added to SMM Gateway if required. By deliberately limiting functionality
+and exploiting backend services, the SMM Gateway SP can be significantly lighter-weight than StMM.
+This option is intended to be used on more resource constrained devices that tend to use u-boot.
+There is of course the possibility that other SMM services will need to be supported in the future.
+In such cases, a judgement should be made as to whether StMM should be used rather than extending the SP.
+
+.. uml:: uml/SmmGatewayOverview.puml
+
+SMM Variable Service
+--------------------
+Overview
+''''''''
+UEFI Variable support is provided by the *smm_variable* service provider component. This service provider
+is structured in the same way as other service providers within the TS project. Features of this
+component are:
+
+ * Source file location: ``components/service/uefi/smm_variable``
+ * Public interface definitions: ``protocols/service/smm_variable``
+ * Can be used with any RPC layer - not tied to MM Communicate RPC.
+ * Volatile and non-volatile storage is accessed via instances of the common *storage_backend* interface.
+
+The *smm-gateway/opteesp* and *smm-gateway/sp* deployments integrate the *smm_variable* service provider with the following:
+
+ * An MM Communicate based RPC endpoint.
+ * A *mock_store* instance for volatile variables.
+ * A *secure_storage_client* for non-volatile variables.
+ * A *crypto client* for signature verification.
+
+During SP initialization, the *smm-gateway* uses pre-configured information to discover a backend secure
+storage SP for NV storage and a crypto SP to verify signatures needed for UEFI variable authentication.
+Crypto SP is accessible only if UEFI_AUTH_VAR is enabled.
+
+The following diagram illustrates how the *smm_variable* service provider is integrated into the *smm-gateway*.
+
+.. image:: image/smm-gateway-layers.svg
+
+Because the *smm_variable* service provider is independent of any particular environment, alternative deployments
+are possible e.g.
+
+ * *smm_variable* service provider running within a GP TA with storage off-loaded to the GP TEE Internal API.
+ * *smm_variable* service provider running within a secure enclave with its own internal flash storage.
+
+Supported Functions
+'''''''''''''''''''
+The *smm_variable* service provider supports the following functions:
+
+.. list-table::
+ :header-rows: 1
+
+ * - SMM Variable Function
+ - Purpose
+ - Backend service interaction
+ * - SMM_VARIABLE_FUNCTION_GET_VARIABLE
+ - Get variable data identified by GUID/name.
+ - Query index and get object from appropriate storage backend.
+ * - SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
+ - Called multiple times to enumerate stored variables.
+ - Find variable in index and return next.
+ * - SMM_VARIABLE_FUNCTION_SET_VARIABLE
+ - Adds a new variable or updates an existing one.
+ - | Sets object in storage backend and if necessary, updates index
+ | and syncs to storage.
+ * - SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
+ - Returns information about the variable store.
+ - Iterates over stored variables to determine space used.
+ * - SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
+ - Called by OS when boot phase is complete.
+ - | Updates view of runtime state held by smm_variable service provider.
+ | State variable used when implementing state dependent access control.
+ * - SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
+ - | Set constraints that are checked on the SetVariable operation.
+ | Allows a platform to set check policy.
+ - | Variable index holds variable check constraints object for each variable.
+ | This is updated by this function.
+ * - SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
+ - Get the variable check constraints.
+ - Reads the variable check constraints object.
+ * - SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE
+ - | Returns the maximum variable data size, excluding any
+ | auth header.
+ - | Considers size constraints imposed by backend stores and RPC response
+ | payload constraints.
+
+Supported Variable Attributes
+'''''''''''''''''''''''''''''
+The following variable attributes are supported:
+
+.. list-table::
+ :widths: 3 1 3
+ :header-rows: 1
+
+ * - SMM Variable Attribute
+ - Support
+ - Comment
+ * - EFI_VARIABLE_NON_VOLATILE
+ - yes
+ - Determines which storage backend is used.
+ * - EFI_VARIABLE_BOOTSERVICE_ACCESS
+ - yes
+ - Boot service access controlled by smm_variable service provider.
+ * - EFI_VARIABLE_RUNTIME_ACCESS
+ - yes
+ - Runtime access controlled by smm_variable service provider.
+ * - EFI_VARIABLE_HARDWARE_ERROR_RECORD
+ - no
+ - If the attribute contains this value, VariableName and VendorGuid must comply with the rules
+ stated in Section 8.2.4.2 and Appendix P of the standard.
+ * - EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ - no
+ - DEPRECATED
+ * - EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS
+ - no
+ - Authentication with EFI_VARIABLE_AUTHENTICATION_3 descriptor is enabled.
+ * - EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+ - yes
+ - Authentication with EFI_VARIABLE_AUTHENTICATION_2 descriptor is enabled.
+ * - EFI_VARIABLE_APPEND_WRITE
+ - yes
+ - Implemented by overwriting entire variable data.
+
+Limitations
+'''''''''''
+
+.. list-table::
+ :header-rows: 1
+
+ * - Description
+ - Value
+ * - Maximum size of a single variable
+ - 4096 bytes
+ * - Supported type of signature list element
+ - DER-encoded X.509 certificates
+ * - Supported type of public keys
+ - DER-encoded SignedData structure per PKCS#7 version 1.5, with or without a DER-encoded
+ ContentInfo structure per PKCS#7 version 1.5.
+
+Variable authentication
+'''''''''''''''''''''''
+
+UEFI variable authentication is a method to ensure that a UEFI variable can only be modified
+by those who has proper rights. This restricts only the writing of these variables, while reading
+is only limited by the state of the system (boot versus runtime access).
+
+Key Store Variables
+```````````````````
+Key Store variables store authentication keys, and have predefined special names to specify the
+keys scope (area of effect). When a write access to a variable with an active
+EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is being made, the signature part of
+the write access will be verified against the appropriate key Store variable.
+Access will only be granted if the signature is valid.
+
+The following table lists which Key Store variables defined by the UEFI standard are implemented.
+
+.. list-table::
+ :header-rows: 1
+
+ * - Variable name
+ - Description
+ - Supported
+ * - Platform Key (PK)
+ - Root of trust. If it is not set the authentication is disabled, all write requests are successful.
+ - yes
+ * - Key Exchange Key Database (KEK)
+ - Protects key store databases from unauthorized modifications.
+ - yes
+ * - Signature Database (db)
+ - If a variable write request is signed by the public key whose private pair is
+ stored here the authentication will pass.
+ - yes
+ * - Blacklist Signature Database (dbx)
+ - Contains signatures of software that must not run on the platform.
+ - no
+ * - Authorized Recovery Signature Database (dbr)
+ - Contains signatures of software that can be run for recovery.
+ - no
+ * - Timestamp Signature Database (dbt)
+ - Same as db, but the timestamp of the certificate is also verified.
+ - no
+
+There is no support for initializing the values of the read-only global variables containing
+default values of the key store variables (e.g. PKDefault, KEKDefault, etc.).
+
+The following diagram shows variable authentication hierarchy.
+
+*A → B means A has the right to verify write request to B*
+
+.. uml::
+
+ @startuml
+ [PK] --> [PK]
+ [PK] --> [KEK]
+ [PK] --> [db]
+ [KEK] --> [db]
+ [db] --> [Common Variable]
+ @enduml
+
+Authenticated Variable Lifecycle
+````````````````````````````````
+
+.. uml::
+
+ @startuml
+
+ start
+ if (Is authentication enabled?)
+ if (Enable authentication?) then (yes)
+ :Key Provision
+ {{
+ hide empty description
+
+ state "Set PK" as keyprovision1
+ state "Set KEK (write request must be signed by PK)" as keyprovision2
+ state "Set db (write request must be signed with PK or KEK)" as keyprovision3
+
+ keyprovision1 --> keyprovision2
+ keyprovision2 --> keyprovision3
+ }}
+ ;
+ endif
+ else (yes)
+ switch (Request)
+ case (Clear store\n(disable authentication))
+ :Clear Store
+ {{
+ hide empty description
+
+ state "Delete PK (write request must be signed with PK)" as delete1
+ state "Delete KEK or db (authentication is disabled, so signature is not verified)" as delete2
+
+ delete1 --> delete2
+ }}
+ ;
+ case (Update keys)
+ :Key Update
+ {{
+ hide empty description
+
+ state "Set PK (write request must be signed by original PK)" as keyupdate1
+ state "Set KEK (write request must be signed by new PK)" as keyupdate2
+ state "Set db (write request must be signed with new PK or new KEK)" as keyupdate3
+
+ keyupdate1 --> keyupdate2
+ keyupdate2 --> keyupdate3
+ }}
+ ;
+ case (Reset factory keys)
+
+ skinparam partitionBorderColor red
+ partition "**NOT IMPLEMENTED**" {
+ switch (Recovery method)
+ case ()
+ :Using Setup Mode
+ {{
+ hide empty description
+
+ state "Enter Setup Mode to disable authentication" as recovery1
+ state "Delete PK, KEK, db (signatures are not verified in this mode)" as recovery2
+ state "Leave setup mode, but authentication is still disabled, because PK is empty" as recovery3
+
+ recovery1 -->recovery2
+ recovery2 -->recovery3
+ }}
+ ;
+ case ()
+ :Using default keystores (PKdefault, KEKDefault, dbDefault);
+
+ endswitch
+ }
+
+ case(None)
+ endswitch
+ endif
+
+ end
+
+ @enduml
+
+Variable structure
+``````````````````
+
+.. image:: image/uefi-variable-structure.svg
+
+|
+
+* The elements of the signature verification are stored in or calculated from the fields of the variables:
+ #. Hash: Calculated on Name, GUID, Attributes, Timestamp, Payload fields of the write request
+ #. Public Key: Extracted from the 'Sign. Data' element of the Signature List field in the Payload
+ of the variable responsible for authenticating the request
+ (e.g. in case of KEK request, it will be extracted from PK)
+ #. Signature: Extracted from the 'CertData' field of the write request.
+
+SMM Variable Tests
+''''''''''''''''''
+The following test components exist for the SMM Variable service:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Test Component
+ - Description
+ - Included in deployments
+ * - ``component/service/uefi/smm_variable/backend/test``
+ - | Component tests for the variable_index and variable_store backend
+ | components. Can be run in a native PC environment.
+ - ``deployments/component-test/*``
+ * - ``component/service/uefi/smm_variable/test/service``
+ - | End-to-end service level tests that call service operations from
+ | the perspective of a client.  Can be run in a native PC environment
+ | or on the Arm target platform.
+ - | ``deployments/ts-service-test/*``
+ | ``deployments/uefi-test/*``
+
+SMM Gateway Build Configuration
+-------------------------------
+The smm-gateway SP image may be built using the default configuration parameters defined
+within relevant source files. In practice, it is likely that at least some configuration
+values will need to be overridden. The following table lists build-time configuration
+parameters that may be overridden by global C pre-processor defines.
+
+.. list-table::
+ :widths: 2 2 2 1
+ :header-rows: 1
+
+ * - Config define
+ - Usage
+ - File
+ - Default value
+ * - SMM_GATEWAY_MAX_UEFI_VARIABLES
+ - Maximum number of variables
+ - ``deployments/smm-gateway/common/smm_gateway.c``
+ - 40
+ * - UEFI_MAX_VARIABLE_SIZE
+ - Maximum size of the uefi variables in bytes
+ - ``components/service/uefi/smm_variable/backend/uefi_variable_store.c``
+ - 4096
+ * - SMM_GATEWAY_NV_STORE_SN
+ - The service ID for the backend NV variable store
+ - ``deployments/smm-gateway/common/smm_gateway.c``
+ - Protected Storage SP
+ * - SMM_GATEWAY_CRYPTO_SN
+ - The service ID for the crypto backend
+ - ``deployments/smm-gateway/common/smm_gateway.c``
+ - Crypto SP
+ * - UEFI_AUTH_VAR
+ - Enables or disables UEFI variable authentication
+ - ``components/service/uefi/smm_variable/backend/uefi_variable_store.c``
+ - OFF
+
+MM Communicate RPC Layer
+------------------------
+To maintain compatibility with existing SMM service clients, an MM Communicate based RPC
+layer has been developed that uses the same 'carveout' buffer scheme as StMM. When SMM
+Gateway is used instead of StMM, existing SMM variable clients should interoperate seamlessly.
+The MM Communicate RPC components implement the standard TS RPC interfaces and can be used as
+a general purpose RPC for calls from normal world to secure world. The following MM Communicate
+RPC components have been added:
+
+ * ``components/rpc/mm_communicate/endpoint/sp`` - an RPC endpoint that handles FFA direct
+ calls with MM Communicate and SMM message carried in a shared 'carveout' buffer. Call requests
+ are demultiplexed to the appropriate service interface based on the service GUID carried in
+ the MM Communicate header.  Suitable for use in SP deployments.
+ * ``components/rpc/mm_communicate/caller/linux`` - an RPC caller that calls service operations
+ associated with the destination service interface from Linux user-space. Uses the MM Communicate
+ protocol, sent over FFA using the Debug FFA kernel driver.  Service level tests that run against
+ the SMM Gateway use this RPC caller for invoking SMM service operations.
+
+The following register mapping is assumed for FFA based direct calls to an SP that handles the MM
+Communicate RPC protocol:
+
+.. list-table::
+ :widths: 1 2 2 2
+ :header-rows: 1
+
+ * - Registers
+ - FF-A layer
+ - MM_COMMUNICATE Request
+ - MM_COMMUNICATE Response
+ * - W0
+ - Function ID
+ - | FFA_MSG_SEND_DIRECT_REQ
+ | (0x8400006F/0xC400006F)
+ - | FFA_MSG_SEND_DIRECT_RESP
+ | (0x84000070/0xC4000070)
+ * - W1
+ - Source/Destination ID
+ - Source/Destination ID
+ - Source/Destination ID
+ * - W2/X2
+ - Reserved
+ - 0x00000000
+ - 0x00000000
+ * - W3/X3
+ - Parameter[0]
+ - Data offset in the MM communication buffer
+ - SUCCESS/[MM communicate error code]
+ * - W4/X4
+ - Parameter[1]
+ - 0x00000000
+ - 0x00000000
+ * - W5/X5
+ - Parameter[2]
+ - 0x00000000
+ - 0x00000000
+ * - W6/X6
+ - Parameter[3]
+ - 0x00000000
+ - 0x00000000
+ * - W7/X7
+ - Parameter[4]
+ - 0x00000000
+ - 0x00000000
+
+--------------
+
+*Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/developer/service-descriptions/uml/AttestClaimsModel.puml b/docs/services/uml/AttestClaimsModel.puml
index fb54f71ef..474d03e99 100644
--- a/docs/developer/service-descriptions/uml/AttestClaimsModel.puml
+++ b/docs/services/uml/AttestClaimsModel.puml
@@ -1,5 +1,5 @@
'-------------------------------------------------------------------------------
-' Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+' Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'
diff --git a/docs/developer/service-descriptions/uml/AttestImportedIAKflow.puml b/docs/services/uml/AttestImportedIAKflow.puml
index fef117c05..8abb3a6e4 100644
--- a/docs/developer/service-descriptions/uml/AttestImportedIAKflow.puml
+++ b/docs/services/uml/AttestImportedIAKflow.puml
@@ -1,5 +1,5 @@
'-------------------------------------------------------------------------------
-' Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+' Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'
diff --git a/docs/developer/service-descriptions/uml/AttestPartitioning.puml b/docs/services/uml/AttestPartitioning.puml
index 9e8586292..326cb4d5f 100644
--- a/docs/developer/service-descriptions/uml/AttestPartitioning.puml
+++ b/docs/services/uml/AttestPartitioning.puml
@@ -1,5 +1,5 @@
'-------------------------------------------------------------------------------
-' Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+' Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'
diff --git a/docs/developer/service-descriptions/uml/AttestSelfGeneratedIAKflow.puml b/docs/services/uml/AttestSelfGeneratedIAKflow.puml
index 7fdae1b9a..d35e8a63f 100644
--- a/docs/developer/service-descriptions/uml/AttestSelfGeneratedIAKflow.puml
+++ b/docs/services/uml/AttestSelfGeneratedIAKflow.puml
@@ -1,5 +1,5 @@
'-------------------------------------------------------------------------------
-' Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+' Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'
diff --git a/docs/services/uml/BlockStorageProvider.puml b/docs/services/uml/BlockStorageProvider.puml
new file mode 100644
index 000000000..4f26b2fe2
--- /dev/null
+++ b/docs/services/uml/BlockStorageProvider.puml
@@ -0,0 +1,45 @@
+'-------------------------------------------------------------------------------
+' Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+'
+' SPDX-License-Identifier: BSD-3-Clause
+'
+'-------------------------------------------------------------------------------
+
+@startuml
+
+class rpc_interface {
+ +rpc_status_t {abstract}receive(call_req)
+}
+
+class service_provider {
+ +void init(handlers, num_handlers)
+ +void extend(service_provider)
+ -rpc_status_t receive(call_req)
+}
+
+class block_storage_provider {
+ +void init(block_store)
+ +void regsiter_serializer(encoding, serializer)
+ -rpc_status_t open_handler(call_req)
+ -rpc_status_t close_handler(call_req)
+ -rpc_status_t get_partition_info_handler(call_req)
+ -rpc_status_t read_handler(call_req)
+ -rpc_status_t write_handler(call_req)
+ -rpc_status_t erase_handler(call_req)
+}
+
+class block_store {
+ +int {abstract}open(client_id, uuid, *handle)
+ +int {abstract}close(handle)
+ +int {abstract}get_partition_info(uuid, *partition_info)
+ +int {abstract}read(handle, lba, size, *buffer, *len)
+ +int {abstract}write(handle, lba, *buffer, len)
+ +int {abstract}erase(handle, *lba, num_blocks)
+}
+
+service_provider -up--|> rpc_interface
+block_storage_provider -up--|> service_provider
+block_storage_provider --> block_store
+block_storage_provider --> block_storage_serializer
+
+@enduml
diff --git a/docs/developer/service-descriptions/uml/CryptoProviderClassDiagram.puml b/docs/services/uml/CryptoProviderClassDiagram.puml
index 65c6d83d1..d0176b5d7 100644
--- a/docs/developer/service-descriptions/uml/CryptoProviderClassDiagram.puml
+++ b/docs/services/uml/CryptoProviderClassDiagram.puml
@@ -1,5 +1,5 @@
'-------------------------------------------------------------------------------
-' Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+' Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'
@@ -46,4 +46,4 @@ CryptoProvider ..> MbedCrypto
MbedCrypto ..> SecureStorage
MbedCrypto ..> EntropySource
-@enduml \ No newline at end of file
+@enduml
diff --git a/docs/services/uml/FwStoreClassDiagram.puml b/docs/services/uml/FwStoreClassDiagram.puml
new file mode 100644
index 000000000..228c3db63
--- /dev/null
+++ b/docs/services/uml/FwStoreClassDiagram.puml
@@ -0,0 +1,104 @@
+'-------------------------------------------------------------------------------
+' Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+'
+' SPDX-License-Identifier: BSD-3-Clause
+'
+'-------------------------------------------------------------------------------
+
+@startuml
+
+ class fw_store
+class bank_tracker
+class metadata_manager
+class metadata_serializer
+class installer_index
+class volume_index
+class installer
+class volume
+
+class bank_tracker {
+ +accept()
+ +copy_accept()
+ +set_no_content()
+ +set_holds_content()
+ +set_holds_acceped_content()
+ +is_content()
+ +is_accepted()
+ +is_all_accepted()
+}
+
+class fw_store {
+ +synchronize()
+ +begin_install()
+ +cancel_install()
+ +finalize_install()
+ +select_installer()
+ +write_image()
+ +commit_image()
+ +notify_accepted()
+ +is_accepted()
+ +is_trial()
+ +commit_to_update()
+ +revert_to_previous()
+ +export()
+}
+
+class metadata_manager {
+ +check_and_repair()
+ +update()
+ +get_active_indices()
+ +preload_bank_tracker()
+}
+
+class metadata_serializer {
+ +serialize()
+ +size()
+ +max_size()
+ +deserialize_bank_info()
+ +deserialize_active_indices()
+}
+
+class installer_index {
+ +register()
+ +find()
+ +get()
+ +get_location_ids()
+}
+
+class installer {
+ +begin()
+ +finalize()
+ +abort()
+ +open()
+ +commit()
+ +write()
+ +enumerate()
+}
+
+class volume_index {
+ +add()
+ +find()
+}
+
+class volume {
+ +open()
+ +close()
+ +seek()
+ +size()
+ +read()
+ +write()
+ +erase()
+ +get_storage_ids()
+}
+
+fw_store -> metadata_manager
+fw_store -> bank_tracker
+fw_store -> installer_index
+fw_store -> volume_index
+metadata_manager -> metadata_serializer
+installer_index -> "*" installer
+volume_index -> "*" volume
+metadata_manager -> "2" volume
+installer ..> volume
+
+@enduml
diff --git a/docs/developer/service-descriptions/uml/InternalTrustedDeploymentDiagram.puml b/docs/services/uml/InternalTrustedDeploymentDiagram.puml
index 13d26b0e7..ccc247570 100644
--- a/docs/developer/service-descriptions/uml/InternalTrustedDeploymentDiagram.puml
+++ b/docs/services/uml/InternalTrustedDeploymentDiagram.puml
@@ -1,5 +1,5 @@
'-------------------------------------------------------------------------------
-' Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+' Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'
@@ -17,4 +17,4 @@ node internal_trusted_store_sp {
[secure_storage_client] -> [secure_storage_provider]
-@enduml \ No newline at end of file
+@enduml
diff --git a/docs/developer/service-descriptions/uml/ProtectedProxyDeploymentDiagram.puml b/docs/services/uml/ProtectedProxyDeploymentDiagram.puml
index a6d5c1405..1ce52edaf 100644
--- a/docs/developer/service-descriptions/uml/ProtectedProxyDeploymentDiagram.puml
+++ b/docs/services/uml/ProtectedProxyDeploymentDiagram.puml
@@ -1,5 +1,5 @@
'-------------------------------------------------------------------------------
-' Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+' Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'
@@ -22,4 +22,4 @@ node sel1_sp {
[secure_storage_client:0] -> [secure_storage_provider:1]
[secure_storage_client:1] -> [secure_storage_provider:2]
-@enduml \ No newline at end of file
+@enduml
diff --git a/docs/developer/service-descriptions/uml/SecureStorageClassDiagram.puml b/docs/services/uml/SecureStorageClassDiagram.puml
index 60177eb6c..8e6909cfd 100644
--- a/docs/developer/service-descriptions/uml/SecureStorageClassDiagram.puml
+++ b/docs/services/uml/SecureStorageClassDiagram.puml
@@ -1,5 +1,5 @@
'-------------------------------------------------------------------------------
-' Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+' Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'
@@ -25,4 +25,4 @@ secure_storage_provider -d--> storage_backend
its_frontend -d--> storage_backend
ps_frontend -d--> storage_backend
-@enduml \ No newline at end of file
+@enduml
diff --git a/docs/services/uml/SmmGatewayOverview.puml b/docs/services/uml/SmmGatewayOverview.puml
new file mode 100644
index 000000000..f53d2a430
--- /dev/null
+++ b/docs/services/uml/SmmGatewayOverview.puml
@@ -0,0 +1,14 @@
+'-------------------------------------------------------------------------------
+' Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+'
+' SPDX-License-Identifier: BSD-3-Clause
+'
+'-------------------------------------------------------------------------------
+
+@startuml
+
+[u-boot efi services] -down- [smm gateway]
+[smm gateway] -down- [secure storage service]
+[smm gateway] -down- [crypto service]
+
+@enduml
diff --git a/docs/services/uml/UpdateAgentClassDiagram.puml b/docs/services/uml/UpdateAgentClassDiagram.puml
new file mode 100644
index 000000000..0dad62737
--- /dev/null
+++ b/docs/services/uml/UpdateAgentClassDiagram.puml
@@ -0,0 +1,100 @@
+'-------------------------------------------------------------------------------
+' Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+'
+' SPDX-License-Identifier: BSD-3-Clause
+'
+'-------------------------------------------------------------------------------
+
+@startuml
+
+class fw_directory
+class fw_inspector
+class img_dir_serializer
+class stream_manager
+class update_agent
+class fw_store
+class installer
+
+class update_agent {
+ +begin_staging()
+ +end_staging()
+ +cancel_staging()
+ +accept()
+ +select_previous()
+ +open()
+ +commit()
+ +read_stream()
+ +write_stream()
+}
+
+class fw_directory {
+ +set_boot_info()
+ +add_image_info()
+ +find_image_info()
+ +get_image_info()
+ +num_images()
+}
+
+class fw_inspector {
+ +inspect
+}
+
+class img_dir_serializer {
+ +serialize()
+ +get_len()
+}
+
+class stream_manager {
+ +open_buffer_stream()
+ +open_install_stream()
+ +close_stream()
+ +cancel_streams()
+ +is_open_streams()
+ +read()
+ +write()
+}
+
+class fw_store {
+ +synchronize()
+ +begin_install()
+ +cancel_install()
+ +finalize_install()
+ +select_installer()
+ +write_image()
+ +commit_image()
+ +notify_accepted()
+ +is_accepted()
+ +is_trial()
+ +commit_to_update()
+ +revert_to_previous()
+ +export()
+}
+
+class installer {
+ +begin()
+ +finalize()
+ +abort()
+ +open()
+ +commit()
+ +write()
+ +enumerate()
+}
+
+class installer_index {
+ +register()
+ +find()
+ +get()
+ +get_location_ids()
+}
+
+update_agent -> fw_store
+update_agent -> fw_directory
+update_agent -> fw_inspector
+update_agent -> stream_manager
+update_agent -> img_dir_serializer
+img_dir_serializer ..> fw_directory
+fw_inspector -> installer_index
+fw_inspector ..> installer
+stream_manager ..> installer
+
+@enduml
diff --git a/docs/standards/ff-a.rst b/docs/standards/ff-a.rst
deleted file mode 100644
index c6a8e39c0..000000000
--- a/docs/standards/ff-a.rst
+++ /dev/null
@@ -1,20 +0,0 @@
-Firmware Framework for Armv8-A
-==============================
-
-|FF-A| is a standard which *"describes interfaces that standardize communication between the various software images. This
-includes communication between images in the Secure world and Normal world."*
-
-Trusted Services is the home of the FF-A S-EL0 Secure Partitions implementing PSA functionality. The component :ref:`libsp`
-captures helpful abstractions to allow easy FF-A compliant S-EL0 SP development. S-EL0 SPs are SPMC agonistic and can be used
-with an SPMC running in any higher secure exception level (S-EL1 - S-EL3). Currently the solution is tested with an SPMC
-running at S-SEL1 integrated into OP-TEE OS.
-
---------------
-
-.. _`PSA homepage`: https://developer.arm.com/architectures/security-architectures/platform-security-architecture
-.. _`www.psacertified.org`: https://www.psacertified.org/certified-products/
-.. _`Hafnium project`: https://www.trustedfirmware.org/projects/hafnium/
-
-*Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.*
-
-SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/standards/index.rst b/docs/standards/index.rst
deleted file mode 100644
index 3ea4651e8..000000000
--- a/docs/standards/index.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-Standards Compliance
-====================
-
-.. toctree::
- :maxdepth: 1
- :caption: Contents:
-
- psa
- ff-a
-
---------------
-
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
-
-SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/standards/psa.rst b/docs/standards/psa.rst
deleted file mode 100644
index 1dbed3902..000000000
--- a/docs/standards/psa.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-Platform Security Architecture
-==============================
-
-Trusted Services is the home of the |PSA| reference implementation. The PSA partitions are implemented based on the |FF-A|
-specification. For details on FF-A support in TS please see the :doc:`ff-a` page.
-
-For background information on |PSA| please visit the `PSA homepage`_. If you are looking for information on certified products
-please visit `www.psacertified.org`_
-
-For a list of PSA specific components refer to deployments targeting the ``opteesp`` environment on the
-:doc:`/developer/deployments` page.
-
---------------
-
-.. _`PSA homepage`: https://developer.arm.com/architectures/security-architectures/platform-security-architecture
-.. _`www.psacertified.org`: https://www.psacertified.org/certified-products/
-.. _`Hafnium project`: https://www.trustedfirmware.org/projects/hafnium/
-
-*Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.*
-
-SPDX-License-Identifier: BSD-3-Clause
diff --git a/docs/target-platforms/aem-fvp.rst b/docs/target-platforms/aem-fvp.rst
new file mode 100644
index 000000000..a2d4ad66c
--- /dev/null
+++ b/docs/target-platforms/aem-fvp.rst
@@ -0,0 +1,20 @@
+AEM FVP
+=======
+
+Arm `Fixed Virtual Platforms`_ are hardware emulators "running at speeds comparable to the real hardware".
+FVP packages are released in various different configurations. This platform supports the
+`Armv-A Base RevC AEM FVP`_
+
+Please see the following chapters of using the AEM FVP:
+
+ - :ref:`Running User-space Programs on FVP`
+
+--------------
+
+.. _`Fixed Virtual Platforms`: https://developer.arm.com/Tools%20and%20Software/Fixed%20Virtual%20Platforms
+.. _`Armv-A Base RevC AEM FVP`: https://developer.arm.com/-/media/Files/downloads/ecosystem-models/FVP_Base_RevC-2xAEMvA_11.18_16_Linux64.tgz
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
+
diff --git a/docs/target-platforms/index.rst b/docs/target-platforms/index.rst
new file mode 100644
index 000000000..49bffb17b
--- /dev/null
+++ b/docs/target-platforms/index.rst
@@ -0,0 +1,39 @@
+Target Platforms
+================
+
+Target platforms are emulated or physically implemented hardware. This chapter discusses platform
+related information.
+
+Platforms can be categorized by level of support as:
+
+ - Reference platforms
+ Reference platforms are "easily" accessible for testing and quality gate-keeping of the main
+ branch includes tests executed on these platforms.
+
+ - Active
+ Platforms in this category are updated and tested by their owners for each release.
+
+ - Obsolete
+ Platforms which are not tested for the current release are put into this category.
+
+ - Deprecated Platforms not tested for more than one two are threated as obsolete, and will be
+ removed for the next release.
+
+The quality of the platform, known issues, feature limitations, extra features, etc... are defined
+in the sub-chapters below.
+
+
+Reference platforms
+-------------------
+
+.. toctree::
+ :maxdepth: 1
+
+ ./aem-fvp
+
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
+
+SPDX-License-Identifier: BSD-3-Clause
diff --git a/environments/arm-linux/default_toolchain_file.cmake b/environments/arm-linux/default_toolchain_file.cmake
index 7ac162169..1da144e13 100644
--- a/environments/arm-linux/default_toolchain_file.cmake
+++ b/environments/arm-linux/default_toolchain_file.cmake
@@ -1,19 +1,56 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
+
+# Since we append to default compilation flags stop multiple inclusion to avoid
+# flags being added multiple times.
+include_guard(GLOBAL)
+
if(NOT CROSS_COMPILE AND NOT DEFINED ENV{CROSS_COMPILE})
- set(CROSS_COMPILE "aarch64-linux-gnu-;aarch64-none-linux-gnu-" CACHE STRING "List of GCC prefix triplets to use.")
+ set(CROSS_COMPILE "aarch64-linux-gnu-;aarch64-none-linux-gnu-" CACHE STRING "List of GCC prefix triplets to use.")
endif()
set(CMAKE_CROSSCOMPILING True)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
-set(CMAKE_C_FLAGS_INIT "-fdiagnostics-show-option -gdwarf-2 -mstrict-align -O0 -DARM64=1")
-set(CMAKE_CXX_FLAGS_INIT "-fdiagnostics-show-option -gdwarf-2 -mstrict-align -O0 -DARM64=1")
+set(TS_DEBUG_INFO_FLAGS "-fdiagnostics-show-option -gdwarf-2" CACHE STRING "Compiler flags to add debug information.")
+set(TS_MANDATORY_AARCH_FLAGS "-mstrict-align -march=armv8-a+crc -DARM64=1" CACHE STRING "Compiler flags configuring architecture specific ")
+set(TS_WARNING_FLAGS "-Wall -Werror" CACHE STRING "Compiler flags affecting generating warning messages.")
+set(TS_MANDATORY_LINKER_FLAGS "" CACHE STRING "Linker flags needed for correct builds.")
+
+# Set flags affecting all build types
+foreach(_b_type IN ITEMS DEBUG MINSIZEREL MINSIZWITHDEBINFO RELEASE RELWITHDEBINFO)
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_AARCH_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_AARCH_FLAGS}")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_LINKER_FLAGS}")
+ if(DEFINED TS_ROOT)
+ # Flags not to be used with external components.
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_WARNING_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_WARNING_FLAGS}")
+ endif()
+endforeach()
+
+# Set flags affecting all build types supporting debugging.
+foreach(_b_type IN ITEMS DEBUG RELWITHDEBINFO MINSIZWITHDEBINFO)
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_DEBUG_INFO_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_DEBUG_INFO_FLAGS}")
+endforeach()
+
+# Build type specific flags
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -O0")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_C_FLAGS_MINSIZWITHDEBINFO_INIT " -Os")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -O2")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -O2")
+string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -O0")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZWITHDEBINFO_INIT " -Os")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -O2")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -O2")
include($ENV{TS_ROOT}/tools/cmake/compiler/GCC.cmake REQUIRED)
include($ENV{TS_ROOT}/tools/cmake/compiler/config_iface.cmake REQUIRED)
diff --git a/environments/linux-pc/component.cmake b/environments/linux-pc/component.cmake
new file mode 100644
index 000000000..bcdb6adc5
--- /dev/null
+++ b/environments/linux-pc/component.cmake
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+if (NOT DEFINED TRACE_PREFIX)
+ message(FATAL_ERROR "mandatory parameter TRACE_PREFIX is not defined.")
+endif()
+
+# Default to trace output disabled
+set(TRACE_LEVEL "TRACE_LEVEL_NONE" CACHE STRING "Trace level")
+
+target_compile_definitions(${TGT} PRIVATE
+ TRACE_LEVEL=${TRACE_LEVEL}
+ TRACE_PREFIX="${TRACE_PREFIX}"
+)
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/posix_trace.c"
+ )
diff --git a/environments/linux-pc/default_toolchain_file.cmake b/environments/linux-pc/default_toolchain_file.cmake
index 6978dbf74..58f29bcf8 100644
--- a/environments/linux-pc/default_toolchain_file.cmake
+++ b/environments/linux-pc/default_toolchain_file.cmake
@@ -1,8 +1,48 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
+# Since we append to default compilation flags stop multiple inclusion to avoid
+# flags being added multiple times.
+include_guard(GLOBAL)
+
+set(TS_DEBUG_INFO_FLAGS "-fdiagnostics-show-option -gdwarf-2" CACHE STRING "Compiler flags to add debug information.")
+set(TS_MANDATORY_AARCH_FLAGS "" CACHE STRING "Compiler flags configuring architecture specific ")
+set(TS_WARNING_FLAGS "-Wall -Werror" CACHE STRING "Compiler flags affecting generating warning messages.")
+set(TS_MANDATORY_LINKER_FLAGS "" CACHE STRING "Linker flags needed for correct builds.")
+
+# Set flags affecting all build types
+foreach(_b_type IN ITEMS DEBUG MINSIZEREL MINSIZWITHDEBINFO RELEASE RELWITHDEBINFO)
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_AARCH_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_AARCH_FLAGS}")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_LINKER_FLAGS}")
+ if(DEFINED TS_ROOT)
+ # Flags not to be used with external components.
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_WARNING_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_WARNING_FLAGS}")
+ endif()
+endforeach()
+
+# Set flags affecting all build types supporting debugging.
+foreach(_b_type IN ITEMS DEBUG RELWITHDEBINFO MINSIZWITHDEBINFO)
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_DEBUG_INFO_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_DEBUG_INFO_FLAGS}")
+endforeach()
+
+# Build type specific flags
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -O0")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_C_FLAGS_MINSIZWITHDEBINFO_INIT " -Os")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -O2")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -O2")
+string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -O0")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZWITHDEBINFO_INIT " -Os")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -O2")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -O2")
+
+include($ENV{TS_ROOT}/tools/cmake/compiler/GCC.cmake REQUIRED)
include($ENV{TS_ROOT}/tools/cmake/compiler/config_iface.cmake REQUIRED)
diff --git a/environments/linux-pc/posix_trace.c b/environments/linux-pc/posix_trace.c
new file mode 100644
index 000000000..2e6b8cbfd
--- /dev/null
+++ b/environments/linux-pc/posix_trace.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <stdio.h>
+
+#include "trace.h"
+
+#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
+
+void trace_puts(const char *str)
+{
+ puts(str);
+}
+
+#endif /* TRACE_LEVEL >= TRACE_LEVEL_ERROR */
diff --git a/environments/opteesp/ExportSp.cmake b/environments/opteesp/ExportSp.cmake
deleted file mode 100644
index c8d74fab4..000000000
--- a/environments/opteesp/ExportSp.cmake
+++ /dev/null
@@ -1,46 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-foreach(_var IN ITEMS EXPORT_SP_NAME EXPORT_SP_UUID)
- if(NOT DEFINED ${_var})
- message(FATAL_ERROR
- "Input variable ${_var} is undefined! Please define it"
- "using set(${_var} ...) before including this file.")
- endif()
-endforeach()
-
-configure_file(${CMAKE_CURRENT_LIST_DIR}/sp.mk.in ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_NAME}.mk @ONLY NEWLINE_STYLE UNIX)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_NAME}.mk DESTINATION ${TS_ENV}/lib/make)
-
-get_filename_component(PARENT_LIST_DIR ${CMAKE_PARENT_LIST_FILE} DIRECTORY)
-string(REGEX REPLACE
- "([a-f0-9]+)-([a-f0-9]+)-([a-f0-9]+)-([a-f0-9]+)-([a-f0-9][a-f0-9][a-f0-9][a-f0-9])([a-f0-9]+)"
- "0x\\1 0x\\2\\3 0x\\4\\5 0x\\6"
- EXPORT_SP_UUID_DT ${EXPORT_SP_UUID})
-
-set(DTS_TAG "")
-set(DTS_NODE "${EXPORT_SP_NAME}")
-configure_file(${PARENT_LIST_DIR}/default_${EXPORT_SP_NAME}.dts.in
- ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_UUID}.dtsi @ONLY NEWLINE_STYLE UNIX)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_UUID}.dtsi DESTINATION ${TS_ENV}/manifest)
-
-set(DTS_TAG "/dts-v1/;")
-set(DTS_NODE "/")
-configure_file(${PARENT_LIST_DIR}/default_${EXPORT_SP_NAME}.dts.in
- ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_UUID}.dts @ONLY NEWLINE_STYLE UNIX)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_UUID}.dts DESTINATION ${TS_ENV}/manifest)
-
-configure_file(${CMAKE_CURRENT_LIST_DIR}/sp_pkg.json.in
- ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_NAME}.json @ONLY NEWLINE_STYLE UNIX)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_NAME}.json DESTINATION ${TS_ENV}/json)
-
-unset(DTS_TAG)
-unset(DTS_NODE)
-unset(PARENT_LIST_DIR)
-unset(EXPORT_SP_UUID_DT)
-unset(EXPORT_SP_NAME)
-unset(EXPORT_SP_UUID)
diff --git a/environments/opteesp/component.cmake b/environments/opteesp/component.cmake
index f6a65cdd4..2b54682a9 100644
--- a/environments/opteesp/component.cmake
+++ b/environments/opteesp/component.cmake
@@ -1,19 +1,44 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-if (NOT DEFINED TGT)
- message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+# Check mandatory variables.
+foreach(_var IN ITEMS TGT)
+ if (NOT DEFINED ${_var})
+ message(FATAL_ERROR "Mandatory parameter '${_var}' missing.")
+ endif()
+endforeach()
+
+# Ensure elf output naming is symbolize.py compatible.
+# If binary UUID is not defined, fall back to using the SP UUID value.
+if (NOT SP_BIN_UUID_CANON)
+ set(SP_BIN_UUID_CANON "${SP_FFA_UUID_CANON}")
+endif()
+ts_add_uuid_to_exe_name(TGT "${TGT}" UUID "${SP_BIN_UUID_CANON}" )
+
+get_target_property(_tgt_type ${TGT} TYPE)
+if ("${_tgt_type}" STREQUAL "EXECUTABLE")
+ compiler_generate_stripped_elf(TARGET ${TGT} NAME "${SP_BIN_UUID_CANON}.stripped.elf" RES STRIPPED_ELF)
+ install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
+
+ # Get the name of the SP.
+ get_target_property(_tgt_name ${TGT} NAME )
+ set(SP_NAME "${_tgt_name}" CACHE STRING "Name of the SP.")
+
+ include(${TS_ROOT}/tools/cmake/common/TargetCompileDefinitions.cmake)
+ set_target_uuids(
+ SP_UUID ${SP_FFA_UUID_CANON}
+ TGT ${SP_NAME}
+ )
+
endif()
target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/optee_sp_header.c"
- "${CMAKE_CURRENT_LIST_DIR}/newlib_init.c"
- "${CMAKE_CURRENT_LIST_DIR}/newlib_sp_assert.c"
- "${CMAKE_CURRENT_LIST_DIR}/newlib_sp_heap.c"
+ "${CMAKE_CURRENT_LIST_DIR}/sp_assert.c"
"${CMAKE_CURRENT_LIST_DIR}/sp_entry.c"
"${CMAKE_CURRENT_LIST_DIR}/sp_trace.c"
)
@@ -28,16 +53,20 @@ target_include_directories(${TGT}
set(TRACE_PREFIX "SP" CACHE STRING "Trace prefix")
set(TRACE_LEVEL "TRACE_LEVEL_ERROR" CACHE STRING "Trace level")
+if (NOT DEFINED SP_HEAP_SIZE)
+ message(FATAL_ERROR "SP_HEAP_SIZE is not defined")
+endif()
+
target_compile_definitions(${TGT} PRIVATE
TRACE_LEVEL=${TRACE_LEVEL}
TRACE_PREFIX="${TRACE_PREFIX}"
+ SP_HEAP_SIZE=${SP_HEAP_SIZE}
)
-include(../../../external/newlib/newlib.cmake)
+include(${TS_ROOT}/external/newlib/newlib.cmake)
target_link_libraries(${TGT} PRIVATE
- c
- nosys
+ stdlib::c
)
target_link_options(${TGT} PRIVATE
diff --git a/environments/opteesp/default_toolchain_file.cmake b/environments/opteesp/default_toolchain_file.cmake
index f0e02770a..43c19c510 100644
--- a/environments/opteesp/default_toolchain_file.cmake
+++ b/environments/opteesp/default_toolchain_file.cmake
@@ -1,10 +1,14 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
+# Since we append to default compilation flags stop multiple inclusion to avoid
+# flags being added multiple times.
+include_guard(GLOBAL)
+
#GNUARM v8 and v9 compilers use a different triplet.
if(NOT CROSS_COMPILE AND NOT DEFINED ENV{CROSS_COMPILE})
set(CROSS_COMPILE "aarch64-elf-;aarch64-none-elf-;aarch64-linux-gnu-;aarch64-none-linux-gnu-" CACHE STRING "List of GCC prefix triplets to use.")
@@ -15,20 +19,41 @@ set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_POSITION_INDEPENDENT_CODE True)
+set(TS_DEBUG_INFO_FLAGS "-fdiagnostics-show-option -gdwarf-2" CACHE STRING "Compiler flags to add debug information.")
+set(TS_MANDATORY_AARCH_FLAGS "-fpic -mstrict-align -march=armv8-a+crc" CACHE STRING "Compiler flags configuring architecture specific ")
+set(TS_WARNING_FLAGS "-Wall -Werror" CACHE STRING "Compiler flags affecting generating warning messages.")
+set(TS_MANDATORY_LINKER_FLAGS "-pie -Wl,--as-needed -Wl,--sort-section=alignment -zmax-page-size=4096"
+ CACHE STRING "Linker flags needed for correct builds.")
+
+# Set flags affecting all build types
+foreach(_b_type IN ITEMS DEBUG MINSIZEREL MINSIZWITHDEBINFO RELEASE RELWITHDEBINFO)
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_AARCH_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_AARCH_FLAGS}")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_LINKER_FLAGS}")
+ if(DEFINED TS_ROOT)
+ # Flags not to be used with external components.
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_WARNING_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_WARNING_FLAGS}")
+ endif()
+endforeach()
+
+# Set flags affecting all build types supporting debugging.
+foreach(_b_type IN ITEMS DEBUG RELWITHDEBINFO MINSIZWITHDEBINFO)
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_DEBUG_INFO_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_DEBUG_INFO_FLAGS}")
+endforeach()
+
+# Build type specific flags
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -O0")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_C_FLAGS_MINSIZWITHDEBINFO_INIT " -Os")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -O2")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -O2")
+string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -O0")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZWITHDEBINFO_INIT " -Os")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -O2")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -O2")
+
include($ENV{TS_ROOT}/tools/cmake/compiler/GCC.cmake REQUIRED)
include($ENV{TS_ROOT}/tools/cmake/compiler/config_iface.cmake REQUIRED)
-# Set mandatory compiler and linker flags for this environment:
-# - This environment uses a libc implementation from SPDEV-KIT. Disable standard
-# include search paths, startup files and default libraries.
-string(APPEND CMAKE_C_FLAGS_INIT " -nostartfiles -nodefaultlibs -nostdinc -I ${CMAKE_CURRENT_LIST_DIR}/include")
-# - Compile position independent code
-string(APPEND CMAKE_C_FLAGS_INIT " -fpic")
-# -set entry point
-# -disable link time optimization
-# -link position independent executable
-string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -e __sp_entry -fno-lto -pie")
-
-# -link libgcc with full PATH to work around disabled linker search paths.
-gcc_get_lib_location("libgcc.a" _TMP_VAR)
-string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " ${_TMP_VAR} ")
-unset(_TMP_VAR)
diff --git a/environments/opteesp/include/libc_init.h b/environments/opteesp/include/libc_init.h
deleted file mode 100644
index 232c3c0b4..000000000
--- a/environments/opteesp/include/libc_init.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#ifndef LIBC_INIT_H_
-#define LIBC_INIT_H_
-
-void libc_init(void);
-
-#endif /* LIBC_INIT_H_ */
diff --git a/environments/opteesp/include/optee_sp_internal_api.h b/environments/opteesp/include/optee_sp_internal_api.h
index d275caa0e..1ffd4c143 100644
--- a/environments/opteesp/include/optee_sp_internal_api.h
+++ b/environments/opteesp/include/optee_sp_internal_api.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifndef OPTEE_SP_INTERNAL_API_H_
@@ -13,7 +13,6 @@
* The SP code base should also contain a header file named
* "optee_sp_user_defines.h" for passing the following definitions to the SP dev
* kit:
- * * OPTEE_SP_HEAP_SIZE: Heap size in bytes
* * OPTEE_SP_UUID: UUID of the SP as an sp_uuid structure
* * OPTEE_SP_STACK_SIZE: Stack size in bytes
* * OPTEE_SP_FLAGS: SP attributes (currently none available, set to zero)
diff --git a/environments/opteesp/include/stdarg.h b/environments/opteesp/include/stdarg.h
deleted file mode 100644
index e260b9b50..000000000
--- a/environments/opteesp/include/stdarg.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-/*
- * Portions copyright (c) 2018, ARM Limited and Contributors.
- * All rights reserved.
- */
-
-#ifndef STDARG_H
-#define STDARG_H
-
-#define va_list __builtin_va_list
-#define va_start(ap, last) __builtin_va_start(ap, last)
-#define va_end(ap) __builtin_va_end(ap)
-#define va_copy(to, from) __builtin_va_copy(to, from)
-#define va_arg(to, type) __builtin_va_arg(to, type)
-
-#endif /* STDARG_H */
diff --git a/environments/opteesp/include/stdbool.h b/environments/opteesp/include/stdbool.h
deleted file mode 100644
index b58334cd0..000000000
--- a/environments/opteesp/include/stdbool.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef STDBOOL_H
-#define STDBOOL_H
-
-#define bool _Bool
-
-#define true (0 < 1)
-#define false (0 > 1)
-
-#define __bool_true_false_are_defined 1
-
-#endif /* STDBOOL_H */
diff --git a/environments/opteesp/include/stddef.h b/environments/opteesp/include/stddef.h
deleted file mode 100644
index 58a519e52..000000000
--- a/environments/opteesp/include/stddef.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-/*
- * Portions copyright (c) 2018-2019, ARM Limited and Contributors.
- * All rights reserved.
- */
-
-#ifndef STDDEF_H
-#define STDDEF_H
-
-#include <stddef_.h>
-
-#ifndef _PTRDIFF_T
-typedef long ptrdiff_t;
-#define _PTRDIFF_T
-#endif
-
-#ifndef NULL
-#define NULL ((void *) 0)
-#endif
-
-#define offsetof(st, m) __builtin_offsetof(st, m)
-
-#endif /* STDDEF_H */
diff --git a/environments/opteesp/include/stddef_.h b/environments/opteesp/include/stddef_.h
deleted file mode 100644
index 6ecc6067c..000000000
--- a/environments/opteesp/include/stddef_.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef STDDEF__H
-#define STDDEF__H
-
-#ifndef SIZET_
-typedef unsigned long size_t;
-#define SIZET_
-#endif
-
-#endif /* STDDEF__H */
diff --git a/environments/opteesp/sp.ld.S b/environments/opteesp/sp.ld.S
index a1f3fb320..a3999f22d 100644
--- a/environments/opteesp/sp.ld.S
+++ b/environments/opteesp/sp.ld.S
@@ -2,7 +2,7 @@
/*
* Copyright (c) 2014, STMicroelectronics International N.V. All rights reserved.
* Copyright (c) 2015, Linaro Limited. All rights reserved.
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#ifdef ARM32
OUTPUT_FORMAT("elf32-littlearm")
@@ -51,6 +51,7 @@ SECTIONS {
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.hash : { *(.hash) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
/* Page align to allow dropping execute bit for RW data */
. = ALIGN(4096);
@@ -92,3 +93,6 @@ SECTIONS {
/DISCARD/ : { *(.interp) }
}
+
+ASSERT(sp_head == 0,
+ "sp_head must be at address 0. Please check input sections and linker settings.");
diff --git a/environments/opteesp/newlib_sp_assert.c b/environments/opteesp/sp_assert.c
index 5a2d42876..8f336e78f 100644
--- a/environments/opteesp/newlib_sp_assert.c
+++ b/environments/opteesp/sp_assert.c
@@ -1,16 +1,17 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
-#include <assert.h>
+#include "assert_fail_handler.h"
#include "compiler.h"
#include "trace.h"
/*
* The generic trace function called on assert fail.
*/
-void __noreturn __assert_func(const char *file, int line, const char *func, const char *failedexpr)
+void __noreturn assert_fail_handler(const char *file, int line,
+ const char *func, const char *failedexpr)
{
#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
trace_printf(func, line, TRACE_LEVEL_ERROR, "assertion %s failed", failedexpr);
diff --git a/environments/opteesp/sp_entry.c b/environments/opteesp/sp_entry.c
index 624940797..f7d67cb55 100644
--- a/environments/opteesp/sp_entry.c
+++ b/environments/opteesp/sp_entry.c
@@ -26,5 +26,5 @@ void __noreturn __sp_entry(uintptr_t a0, uintptr_t a1,
libc_init();
- sp_main((struct ffa_init_info *)a0);
+ sp_main((union ffa_boot_info *)a0);
}
diff --git a/environments/opteesp/sp_pkg.json.in b/environments/opteesp/sp_pkg.json.in
index c7bfb4c6d..02ee474a9 100644
--- a/environments/opteesp/sp_pkg.json.in
+++ b/environments/opteesp/sp_pkg.json.in
@@ -1,6 +1,7 @@
{
"@EXPORT_SP_NAME@": {
- "image": "../bin/@EXPORT_SP_UUID@.stripped.elf",
- "pm": "../manifest/@EXPORT_SP_UUID@.dts"
+ "uuid": "@EXPORT_SP_BIN_UUID_CANON@",
+ "image": "../bin/@EXPORT_SP_BIN_UUID_CANON@.stripped.elf",
+ "pm": "../manifest/@EXPORT_SP_BIN_UUID_CANON@.dts"
}
-} \ No newline at end of file
+}
diff --git a/environments/opteesp/sp_trace.c b/environments/opteesp/sp_trace.c
index 6ac0ddc61..586b41c70 100644
--- a/environments/opteesp/sp_trace.c
+++ b/environments/opteesp/sp_trace.c
@@ -4,15 +4,20 @@
*/
#include "trace.h"
-#include "ffa_internal_api.h"
+#include "ffa_api.h"
+#include <string.h>
#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
void trace_puts(const char *str)
{
- struct ffa_params resp;
+ size_t length = strlen(str);
+ size_t i = 0;
- ffa_svc(0xdeadbeef, (uintptr_t)str, 0, 0, 0, 0, 0, 0, &resp);
+ for (i = 0; i < length; i += FFA_CONSOLE_LOG_64_MAX_LENGTH) {
+ ffa_console_log_64(&str[i], MIN(FFA_CONSOLE_LOG_64_MAX_LENGTH,
+ length - i));
+ }
}
#endif /* TRACE_LEVEL >= TRACE_LEVEL_ERROR */
diff --git a/environments/sp/component.cmake b/environments/sp/component.cmake
new file mode 100644
index 000000000..35532bd7e
--- /dev/null
+++ b/environments/sp/component.cmake
@@ -0,0 +1,51 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Check mandatory variables.
+foreach(_var IN ITEMS TGT TRACE_PREFIX SP_HEAP_SIZE SP_STACK_SIZE SP_FFA_UUID_CANON)
+ if (NOT DEFINED ${_var})
+ message(FATAL_ERROR "Mandatory parameter '${_var}' missing.")
+ endif()
+endforeach()
+
+# Ensure elf output naming is symbolize.py compatible.
+# If binary UUID is not defined, fall back to using the SP UUID value.
+if (NOT SP_BIN_UUID_CANON)
+ set(SP_BIN_UUID_CANON "${SP_FFA_UUID_CANON}")
+endif()
+ts_add_uuid_to_exe_name(TGT "${TGT}" UUID "${SP_BIN_UUID_CANON}" )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/entry.S"
+ "${CMAKE_CURRENT_LIST_DIR}/sp_assert.c"
+ "${CMAKE_CURRENT_LIST_DIR}/sp_entry.c"
+ "${CMAKE_CURRENT_LIST_DIR}/sp_trace.c"
+)
+
+# Default trace level configuration, can be overwritten by setting the same
+# variable in the deployment specific file before including this file.
+set(TRACE_LEVEL "TRACE_LEVEL_ERROR" CACHE STRING "Trace level")
+
+target_compile_definitions(${TGT} PRIVATE
+ TRACE_LEVEL=${TRACE_LEVEL}
+ TRACE_PREFIX="${TRACE_PREFIX}"
+ SP_HEAP_SIZE=${SP_HEAP_SIZE}
+)
+
+include(${TS_ROOT}/external/newlib/newlib.cmake)
+
+target_link_libraries(${TGT} PRIVATE
+ stdlib::c
+)
+
+target_link_options(${TGT} PRIVATE
+ -Wl,--hash-style=sysv
+ -Wl,--as-needed
+ -Wl,--gc-sections
+)
+
+compiler_set_linker_script(TARGET ${TGT} FILE ${CMAKE_CURRENT_LIST_DIR}/sp.ld.S DEF ARM64=1 SP_STACK_SIZE=${SP_STACK_SIZE})
diff --git a/environments/sp/default_toolchain_file.cmake b/environments/sp/default_toolchain_file.cmake
new file mode 100644
index 000000000..31febe556
--- /dev/null
+++ b/environments/sp/default_toolchain_file.cmake
@@ -0,0 +1,58 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Since we append to default compilation flags stop multiple inclusion to avoid
+# flags being added multiple times.
+include_guard(GLOBAL)
+
+#GNUARM v8 and v9 compilers use a different triplet.
+if(NOT CROSS_COMPILE AND NOT DEFINED ENV{CROSS_COMPILE})
+ set(CROSS_COMPILE "aarch64-elf-;aarch64-none-elf-;aarch64-linux-gnu-;aarch64-none-linux-gnu-" CACHE STRING "List of GCC prefix triplets to use.")
+endif()
+
+set(CMAKE_CROSSCOMPILING True)
+set(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR arm)
+set(CMAKE_POSITION_INDEPENDENT_CODE True)
+
+set(TS_DEBUG_INFO_FLAGS "-fdiagnostics-show-option -gdwarf-2" CACHE STRING "Compiler flags to add debug information.")
+set(TS_MANDATORY_AARCH_FLAGS "-fpie -mstrict-align -march=armv8-a+crc" CACHE STRING "Compiler flags configuring architecture specific ")
+set(TS_WARNING_FLAGS "-Wall" CACHE STRING "Compiler flags affecting generating warning messages.")
+set(TS_MANDATORY_LINKER_FLAGS "-Wl,-pie -Wl,--no-dynamic-linker -Wl,--sort-section=alignment -zmax-page-size=4096" CACHE STRING "Linker flags needed for correct builds.")
+
+# Set flags affecting all build types
+foreach(_b_type IN ITEMS DEBUG MINSIZEREL MINSIZWITHDEBINFO RELEASE RELWITHDEBINFO)
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_AARCH_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_AARCH_FLAGS}")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_${_b_type}_INIT " ${TS_MANDATORY_LINKER_FLAGS}")
+ if(DEFINED TS_ROOT)
+ # Flags not to be used with external components.
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_WARNING_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_WARNING_FLAGS}")
+ endif()
+endforeach()
+
+# Set flags affecting all build types supporting debugging.
+foreach(_b_type IN ITEMS DEBUG RELWITHDEBINFO MINSIZWITHDEBINFO)
+ string(APPEND CMAKE_C_FLAGS_${_b_type}_INIT " ${TS_DEBUG_INFO_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS_${_b_type}_INIT " ${TS_DEBUG_INFO_FLAGS}")
+endforeach()
+
+# Build type specific flags
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -O0")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_C_FLAGS_MINSIZWITHDEBINFO_INIT " -Os")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -O2")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -O2")
+string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -O0")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZWITHDEBINFO_INIT " -Os")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -O2")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -O2")
+
+include($ENV{TS_ROOT}/tools/cmake/compiler/GCC.cmake REQUIRED)
+include($ENV{TS_ROOT}/tools/cmake/compiler/config_iface.cmake REQUIRED)
diff --git a/environments/sp/entry.S b/environments/sp/entry.S
new file mode 100644
index 000000000..29c61c388
--- /dev/null
+++ b/environments/sp/entry.S
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <asm.S>
+
+#define R_AARCH64_RELATIVE 1027
+
+/**
+ * The following code is responsible for setting the initial value of the stack
+ * pointer and doing relocation on SP boot.
+ */
+FUNC __sp_entry, :
+ /* Use __stack_end linker symbol to set the load relative stack address. */
+ adrp x4, __stack_end
+ add x4, x4, :lo12:__stack_end
+ mov sp, x4
+
+ /*
+ * X4 = load address
+ * X5 = relocation table start
+ * X6 = relocation table end
+ */
+ adr x4, __sp_entry
+ adrp x5, __rela_start
+ add x5, x5, :lo12:__rela_start
+ adrp x6, __rela_end
+ add x6, x6, :lo12:__rela_end
+
+ /* Iterating through relocation entries */
+ cmp x5, x6
+ beq 2f
+
+ /*
+ * Loading relocation entry
+ * X7 = r_offset
+ * X8 = r_info
+ * X9 = r_addend
+ */
+1: ldp x7, x8, [x5], #16
+ ldr x9, [x5], #8
+
+ /* Only R_AARCH64_RELATIVE type is supported */
+ cmp w8, #R_AARCH64_RELATIVE
+ bne relocation_error
+
+ /*
+ * Apply relative adjustment on address
+ * *(load_address + r_offset) = load_address + r_addend
+ */
+ add x9, x9, x4
+ str x9, [x7, x4]
+
+ cmp x5, x6
+ bne 1b
+
+2:
+ /* Clear BSS */
+ adrp x4, __bss_start
+ add x4, x4, :lo12:__bss_start
+ adrp x5, __bss_end
+ add x5, x5, :lo12:__bss_end
+
+ cmp x4, x5
+ b.eq clear_bss_end
+
+clear_bss:
+ str xzr, [x4], #8
+ cmp x4, x5
+ b.lt clear_bss
+
+clear_bss_end:
+ b _sp_entry
+
+relocation_error:
+ adr X0, error_invalid_relocation
+ bl trace_puts
+ b .
+
+ .align 8
+error_invalid_relocation:
+ .asciz "Only R_AARCH64_RELATIVE type relocation is supported"
+ .align 8
+END_FUNC __sp_entry
diff --git a/environments/sp/env.cmake b/environments/sp/env.cmake
new file mode 100644
index 000000000..bff12368c
--- /dev/null
+++ b/environments/sp/env.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Environment file for generic SP deployments. This is a cross-compiled
+# environment where built executables run within secure partitions with
+# standard binary format that can be loaded by any secure partition manager.
+#-------------------------------------------------------------------------------
+set(TS_ENV "sp" CACHE STRING "Environment identifier")
+
+# Default to using the base toolcahin file for the environment
+set(TS_BASE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/default_toolchain_file.cmake" CACHE STRING "Base toolchainfile")
+
+# Replicate in environment variable for access from child cmake contexts
+set(ENV{TS_BASE_TOOLCHAIN_FILE} "${TS_BASE_TOOLCHAIN_FILE}")
+
+# Set toolchain files to use
+set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/default_toolchain_file.cmake" CACHE STRING "Toolchain file")
+set(TS_EXTERNAL_LIB_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" CACHE STRING "External lib Toolchain file")
diff --git a/environments/sp/newlib_init.c b/environments/sp/newlib_init.c
new file mode 100644
index 000000000..9adf0f237
--- /dev/null
+++ b/environments/sp/newlib_init.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "libc_init.h"
+
+/* Comes from libc */
+void __libc_init_array(void);
+
+void _init(void)
+{
+ /* Dummy */
+}
+
+void libc_init(void)
+{
+ /* Initializing global variables, calling constructors */
+ __libc_init_array();
+}
diff --git a/environments/sp/sp.ld.S b/environments/sp/sp.ld.S
new file mode 100644
index 000000000..7a57a972d
--- /dev/null
+++ b/environments/sp/sp.ld.S
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: BSD-2-Clause AND BSD-3-Clause */
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V. All rights reserved.
+ * Copyright (c) 2015, Linaro Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ */
+#ifdef ARM32
+OUTPUT_FORMAT("elf32-littlearm")
+OUTPUT_ARCH(arm)
+#endif
+#ifdef ARM64
+OUTPUT_FORMAT("elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+#endif
+
+ENTRY(__sp_entry)
+
+SECTIONS {
+ .text : {
+ __text_start = .;
+ *(.text.__sp_entry)
+ *(.text .text.*)
+ *(.stub)
+ *(.glue_7)
+ *(.glue_7t)
+ *(.gnu.linkonce.t.*)
+ /* Workaround for an erratum in ARM's VFP11 coprocessor */
+ *(.vfp11_veneer)
+ __text_end = .;
+ }
+ .plt : { *(.plt) }
+
+ .eh_frame_hdr : {
+ *(.eh_frame_hdr)
+ *(.eh_frame_entry .eh_frame_entry.*)
+ }
+ .eh_frame : { KEEP(*(.eh_frame)) *(.eh_frame.*) }
+ .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
+ .rodata : {
+ *(.gnu.linkonce.r.*)
+ *(.rodata .rodata.*)
+ }
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+ /* .ARM.exidx is sorted, so has to go in its own output section. */
+ PROVIDE_HIDDEN(__exidx_start = .);
+ .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+ PROVIDE_HIDDEN(__exidx_end = .);
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .hash : { *(.hash) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+
+ . = ALIGN(8);
+ __rela_start = .;
+ .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+ .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+ .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+ .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+ .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+ .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+ .rel.dyn : { *(.rel.dyn) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rela.dyn : { *(.rela.dyn) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ __rela_end = .;
+
+ /* Page align to allow dropping execute bit for RW data */
+ . = ALIGN(4096);
+
+ .dynamic : { *(.dynamic) }
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .got : { *(.got.plt) *(.got) }
+
+ .data : { *(.data .data.* .gnu.linkonce.d.*) }
+ .bss : {
+ __bss_start = .;
+ *(.bss .bss.* .gnu.linkonce.b.* COMMON)
+ __bss_end = .;
+ }
+ .stack : {
+ . = ALIGN(4);
+ __stack_start = .;
+ . += SP_STACK_SIZE;
+ . = ALIGN(4);
+ __stack_end = .;
+ }
+
+ /DISCARD/ : { *(.interp) }
+}
+
+ASSERT(__sp_entry == 0,
+ "__sp_entry must be at address 0. Please check input sections and linker settings.");
diff --git a/environments/sp/sp_assert.c b/environments/sp/sp_assert.c
new file mode 100644
index 000000000..8f336e78f
--- /dev/null
+++ b/environments/sp/sp_assert.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "assert_fail_handler.h"
+#include "compiler.h"
+#include "trace.h"
+
+/*
+ * The generic trace function called on assert fail.
+ */
+void __noreturn assert_fail_handler(const char *file, int line,
+ const char *func, const char *failedexpr)
+{
+#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
+ trace_printf(func, line, TRACE_LEVEL_ERROR, "assertion %s failed", failedexpr);
+#endif /* TRACE_LEVEL */
+
+ while (1)
+ ;
+}
diff --git a/environments/sp/sp_entry.c b/environments/sp/sp_entry.c
new file mode 100644
index 000000000..c9b25103d
--- /dev/null
+++ b/environments/sp/sp_entry.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include "compiler.h"
+#include "libc_init.h"
+#include "sp_api.h"
+
+/*
+ * According to the FF-A specification an optional initialization descriptor can
+ * be passed to the SP in w0/x0-w3/x3 registers (a0-a3 parameters). As the exact
+ * register is implementation defined the first four registers are forwarded to
+ * the user code.
+ */
+void __noreturn _sp_entry(uintptr_t a0, uintptr_t a1,
+ uintptr_t a2, uintptr_t a3);
+void __noreturn _sp_entry(uintptr_t a0, uintptr_t a1,
+ uintptr_t a2, uintptr_t a3)
+{
+ (void)a1;
+ (void)a2;
+ (void)a3;
+
+ libc_init();
+
+ sp_main((union ffa_boot_info *)a0);
+}
diff --git a/environments/sp/sp_pkg.json.in b/environments/sp/sp_pkg.json.in
new file mode 100644
index 000000000..23e8805a4
--- /dev/null
+++ b/environments/sp/sp_pkg.json.in
@@ -0,0 +1,7 @@
+{
+ "@EXPORT_SP_NAME@": {
+ "uuid": "@EXPORT_SP_BIN_UUID_CANON@",
+ "image": "../bin/@EXPORT_SP_BIN_UUID_CANON@.bin",
+ "pm": "../manifest/@EXPORT_SP_BIN_UUID_CANON@.dts"
+ }
+} \ No newline at end of file
diff --git a/environments/sp/sp_trace.c b/environments/sp/sp_trace.c
new file mode 100644
index 000000000..7e8cb9c7a
--- /dev/null
+++ b/environments/sp/sp_trace.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "trace.h"
+#include "ffa_api.h"
+#include <string.h>
+
+#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
+
+void trace_puts(const char *str)
+{
+ size_t length = strlen(str);
+ size_t i = 0;
+
+ for (i = 0; i < length; i += FFA_CONSOLE_LOG_64_MAX_LENGTH) {
+ ffa_console_log_64(&str[i], MIN(FFA_CONSOLE_LOG_64_MAX_LENGTH,
+ length - i));
+ }
+}
+
+#endif /* TRACE_LEVEL >= TRACE_LEVEL_ERROR */
diff --git a/external/CppUTest/CppUTest.cmake b/external/CppUTest/CppUTest.cmake
index c18f3e3b5..7b916d521 100644
--- a/external/CppUTest/CppUTest.cmake
+++ b/external/CppUTest/CppUTest.cmake
@@ -1,98 +1,38 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
+
set(CPPUTEST_URL "https://github.com/cpputest/cpputest.git" CACHE STRING "CppUTest repository URL")
set(CPPUTEST_REFSPEC "v3.8" CACHE STRING "CppUTest git refspec")
-set(CPPUTEST_INSTALL_PATH ${CMAKE_CURRENT_BINARY_DIR}/CppUTest_install CACHE PATH "CppUTest installation directory")
-
-include(FetchContent)
+set(CPPUTEST_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/CppUTest_install CACHE PATH "CppUTest installation directory")
+set(CPPUTEST_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/cpputest-src CACHE PATH "CppUTest source directory")
+set(CPPUTEST_BUILD_TYPE "Release" CACHE STRING "CppUTest build type")
-# Checking git
-find_program(GIT_COMMAND "git")
-if (NOT GIT_COMMAND)
- message(FATAL_ERROR "Please install git")
-endif()
-
-# Fetching CppUTest
-FetchContent_Declare(
- cpputest
+set(GIT_OPTIONS
GIT_REPOSITORY ${CPPUTEST_URL}
GIT_TAG ${CPPUTEST_REFSPEC}
- GIT_SHALLOW TRUE
+ GIT_SHALLOW FALSE
PATCH_COMMAND git stash
- COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/cpputest-cmake-fix.patch
-)
-
-# FetchContent_GetProperties exports cpputest_SOURCE_DIR and cpputest_BINARY_DIR variables
-FetchContent_GetProperties(cpputest)
-if(NOT cpputest_POPULATED)
- message(STATUS "Fetching CppUTest")
- FetchContent_Populate(cpputest)
-endif()
-
-# Build and install CppUTest configuration time. This makes us able to use CppUTest as a CMake package.
-# Memory leak detection is turned off to avoid conflict with memcheck.
-if(NOT CMAKE_CROSSCOMPILING)
- execute_process(COMMAND
- ${CMAKE_COMMAND}
- -DMEMORY_LEAK_DETECTION=OFF
- -DLONGLONG=ON
- -DC++11=ON
- -DCMAKE_INSTALL_PREFIX=${CPPUTEST_INSTALL_PATH}
- -DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
- -G${CMAKE_GENERATOR}
- ${cpputest_SOURCE_DIR}
- WORKING_DIRECTORY
- ${cpputest_BINARY_DIR}
- RESULT_VARIABLE
- _exec_error
- )
-else()
- execute_process(COMMAND
- ${CMAKE_COMMAND}
- -DMEMORY_LEAK_DETECTION=OFF
- -DLONGLONG=ON
- -DC++11=ON
- -DCMAKE_INSTALL_PREFIX=${CPPUTEST_INSTALL_PATH}
- -DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
- -DTESTS=OFF
- -DEXTENSIONS=OFF
- -DHAVE_FORK=OFF
- -DCPP_PLATFORM=armcc
- -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY
- -G${CMAKE_GENERATOR}
- ${cpputest_SOURCE_DIR}
- WORKING_DIRECTORY
- ${cpputest_BINARY_DIR}
- RESULT_VARIABLE
- _exec_error
+ COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/cpputest-cmake-fix.patch
)
-endif()
-if (NOT _exec_error EQUAL 0)
- message(FATAL_ERROR "Configuriong CppUTest build failed.")
-endif()
-execute_process(COMMAND
- ${CMAKE_COMMAND}
- --build ${cpputest_BINARY_DIR}
- -- install -j8
- RESULT_VARIABLE
- _exec_error
+
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME CppUTest
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ INSTALL_DIR ${CPPUTEST_INSTALL_DIR}
+ PACKAGE_DIR ${CPPUTEST_INSTALL_DIR}/lib/CppUTest/cmake
+ CACHE_FILE "${TS_ROOT}/external/CppUTest/cpputest-init-cache.cmake.in"
+ SOURCE_DIR ${CPPUTEST_SOURCE_DIR}
)
-if (NOT _exec_error EQUAL 0)
- message(FATAL_ERROR "Building CppUTest failed.")
-endif()
-# Finding CppUTest package. CMake will check [package name]_DIR variable.
-set(CppUTest_DIR ${CPPUTEST_INSTALL_PATH}/lib/CppUTest/cmake CACHE PATH "CppUTest package location" FORCE)
-find_package(CppUTest CONFIG REQUIRED NO_DEFAULT_PATH PATHS ${CppUTest_DIR})
# CppUTest package files do not set include path properties on the targets.
# Fix this here.
foreach(_cpputest_target IN LISTS CppUTest_LIBRARIES)
- if (TARGET ${_cpputest_target})
+ if (TARGET ${_cpputest_target})
target_include_directories(${_cpputest_target} INTERFACE ${CppUTest_INCLUDE_DIRS})
target_compile_features(${_cpputest_target} INTERFACE cxx_std_11)
endif()
diff --git a/external/CppUTest/cpputest-init-cache.cmake.in b/external/CppUTest/cpputest-init-cache.cmake.in
new file mode 100644
index 000000000..b24f5de68
--- /dev/null
+++ b/external/CppUTest/cpputest-init-cache.cmake.in
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX "@BUILD_INSTALL_DIR@" CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE "@TS_EXTERNAL_LIB_TOOLCHAIN_FILE@" CACHE STRING "")
+set(MEMORY_LEAK_DETECTION OFF CACHE BOOL "")
+set(LONGLONG ON CACHE BOOL "")
+set(C++11 ON CACHE BOOL "")
+
+string(TOUPPER @CMAKE_CROSSCOMPILING@ CMAKE_CROSSCOMPILING) # CMake expects TRUE
+if (CMAKE_CROSSCOMPILING)
+ set(TESTS OFF CACHE BOOL "")
+ set(EXTENSIONS OFF BOOL "")
+ set(HAVE_FORK OFF CACHE BOOL "")
+ set(CPP_PLATFORM "armcc" CACHE STRING "")
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE BOOL "")
+endif()
diff --git a/external/LinuxFFAUserShim/LinuxFFAUserShim.cmake b/external/LinuxFFAUserShim/LinuxFFAUserShim.cmake
index 0abdd474c..c0a985187 100644
--- a/external/LinuxFFAUserShim/LinuxFFAUserShim.cmake
+++ b/external/LinuxFFAUserShim/LinuxFFAUserShim.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,47 +8,51 @@
# Find Linux FF-A user space shim repo location.
# It contains a kernel module which exposes FF-A operations to user space using DebugFS.
-# If a CMake variable exists, use it as is.
-# If not, try to copy the value from the environment.
-# If neither is present, try to download.
-if(NOT DEFINED LINUX_FFA_USER_SHIM_DIR)
- if(DEFINED ENV{LINUX_FFA_USER_SHIM_DIR})
- set(LINUX_FFA_USER_SHIM_DIR $ENV{LINUX_FFA_USER_SHIM_DIR}
- CACHE STRING "Linux FF-A user space shim dir")
- else()
- set(LINUX_FFA_USER_SHIM_URL "https://git.gitlab.arm.com/linux-arm/linux-trusted-services.git"
- CACHE STRING "Linux FF-A user space shim repository URL")
- set(LINUX_FFA_USER_SHIM_REFSPEC "v2.1.0"
- CACHE STRING "Linux FF-A user space shim git refspec")
-
- find_program(GIT_COMMAND "git")
- if (NOT GIT_COMMAND)
- message(FATAL_ERROR "Please install git")
- endif()
-
- include(FetchContent)
- FetchContent_Declare(linux_ffa_user_shim
- GIT_REPOSITORY ${LINUX_FFA_USER_SHIM_URL}
- GIT_TAG ${LINUX_FFA_USER_SHIM_REFSPEC}
- GIT_SHALLOW TRUE
- )
-
- # FetchContent_GetProperties exports <name>_SOURCE_DIR and <name>_BINARY_DIR variables
- FetchContent_GetProperties(linux_ffa_user_shim)
- if(NOT linux_ffa_user_shim_POPULATED)
- message(STATUS "Fetching Linux FF-A user space shim")
- FetchContent_Populate(linux_ffa_user_shim)
- endif()
-
- set(LINUX_FFA_USER_SHIM_DIR ${linux_ffa_user_shim_SOURCE_DIR}
- CACHE STRING "Linux FF-A user space shim dir")
- endif()
-endif()
-
+# If the driver is already installed, try to find that
find_path(LINUX_FFA_USER_SHIM_INCLUDE_DIR
NAMES arm_ffa_user.h
- PATHS ${LINUX_FFA_USER_SHIM_DIR}
- NO_DEFAULT_PATH
- REQUIRED
- DOC "Linux FF-A user space shim include directory"
+ DOC "Linux FF-A user space shim driver include directory"
)
+
+# If not found, download it
+if(NOT LINUX_FFA_USER_SHIM_INCLUDE_DIR)
+
+ set(LINUX_FFA_USER_SHIM_URL "https://git.gitlab.arm.com/linux-arm/linux-trusted-services.git"
+ CACHE STRING "Linux FF-A user space shim repository URL")
+
+ # Note: the aim of this external component is to make the header file defining the IOCTL API
+ # available. Fetching a moving reference is ok as long as API compatibility is guaranteed.
+ set(LINUX_FFA_USER_SHIM_REFSPEC "origin/debugfs-v5"
+ CACHE STRING "Linux FF-A user space shim git refspec")
+
+ set(LINUX_FFA_USER_SHIM_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/linux_ffa_user_shim-src"
+ CACHE PATH "Location of Linux driver source.")
+
+ if (DEFINED ENV{LINUX_FFA_USER_SHIM_SOURCE_DIR})
+ set(LINUX_FFA_USER_SHIM_SOURCE_DIR $ENV{LINUX_FFA_USER_SHIM_SOURCE_DIR}
+ CACHE PATH "Location of Linux driver source." FORCE)
+ endif()
+
+ set(GIT_OPTIONS
+ GIT_REPOSITORY ${LINUX_FFA_USER_SHIM_URL}
+ GIT_TAG ${LINUX_FFA_USER_SHIM_REFSPEC}
+ GIT_SHALLOW FALSE
+ )
+ include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+ LazyFetch_MakeAvailable(
+ DEP_NAME linux_ffa_user_shim
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ SOURCE_DIR ${LINUX_FFA_USER_SHIM_SOURCE_DIR}
+ )
+
+ find_path(LINUX_FFA_USER_SHIM_INCLUDE_DIR
+ NAMES arm_ffa_user.h
+ PATHS ${LINUX_FFA_USER_SHIM_SOURCE_DIR}
+ NO_DEFAULT_PATH
+ REQUIRED
+ DOC "Linux FF-A user space shim include directory"
+ )
+endif()
+
+set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
+ "${LINUX_FFA_USER_SHIM_INCLUDE_DIR}/arm_ffa_user.h")
diff --git a/external/LinuxFfaTeeDriver/LinuxFfaTeeDriver.cmake b/external/LinuxFfaTeeDriver/LinuxFfaTeeDriver.cmake
new file mode 100644
index 000000000..da0a5b3de
--- /dev/null
+++ b/external/LinuxFfaTeeDriver/LinuxFfaTeeDriver.cmake
@@ -0,0 +1,54 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# If the driver is already installed, try to find that
+find_path(LINUX_FFA_TEE_DRIVER_INCLUDE_DIR
+ NAMES arm_tstee.h
+ DOC "Linux FF-A TEE driver include directory"
+)
+
+# If not found, download it
+if(NOT LINUX_FFA_TEE_DRIVER_INCLUDE_DIR)
+ set(LINUX_FFA_TEE_DRIVER_URL "https://git.gitlab.arm.com/linux-arm/linux-trusted-services.git"
+ CACHE STRING "Linux FF-A TEE driver repository URL")
+
+ # Note: the aim of this external component is to make the header file defining the IOCTL API
+ # available. Fetching a moving reference is ok as long as API compatibility is guaranteed.
+ set(LINUX_FFA_TEE_DRIVER_REFSPEC "origin/tee-v2"
+ CACHE STRING "Linux FF-A TEE driver git refspec")
+
+ set(LINUX_FFA_TEE_DRIVER_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/linux_ffa_tee_driver-src"
+ CACHE PATH "Location of Linux TEE driver source.")
+
+ if (DEFINED ENV{LINUX_FFA_TEE_DRIVER_SOURCE_DIR})
+ set(LINUX_FFA_TEE_DRIVER_SOURCE_DIR $ENV{LINUX_FFA_TEE_DRIVER_SOURCE_DIR}
+ CACHE PATH "Location of Linux TEE driver source." FORCE)
+ endif()
+
+ set(GIT_OPTIONS
+ GIT_REPOSITORY ${LINUX_FFA_TEE_DRIVER_URL}
+ GIT_TAG ${LINUX_FFA_TEE_DRIVER_REFSPEC}
+ GIT_SHALLOW TRUE
+ )
+ include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+ LazyFetch_MakeAvailable(
+ DEP_NAME linux_ffa_tee_driver
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ SOURCE_DIR ${LINUX_FFA_TEE_DRIVER_SOURCE_DIR}
+ )
+
+ find_path(LINUX_FFA_TEE_DRIVER_INCLUDE_DIR
+ NAMES arm_tstee.h
+ PATHS ${LINUX_FFA_TEE_DRIVER_SOURCE_DIR}/uapi
+ NO_DEFAULT_PATH
+ REQUIRED
+ DOC "Linux FF-A TEE driver include directory"
+ )
+endif()
+
+set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
+ "${LINUX_FFA_TEE_DRIVER_INCLUDE_DIR}/arm_tstee.h")
diff --git a/external/MbedTLS/0001-Add-capability-to-selectively-build-libraries.patch b/external/MbedTLS/0001-Add-capability-to-selectively-build-libraries.patch
new file mode 100644
index 000000000..2f31613a5
--- /dev/null
+++ b/external/MbedTLS/0001-Add-capability-to-selectively-build-libraries.patch
@@ -0,0 +1,144 @@
+From ee65a0f8164db4531d35aa40db7b2f066cd333d7 Mon Sep 17 00:00:00 2001
+From: Gyorgy Szing <Gyorgy.Szing@arm.com>
+Date: Tue, 28 Mar 2023 18:20:44 +0200
+Subject: [PATCH 1/1] Add capability to selectively build libraries
+
+Introduce the BUILD_X509 and BUILD_TLS options which allows disabling
+or enabling building of these libraries.
+
+Uptream-status: Invalid [other]
+ - This is a Trusted Services specific change, there is no intention
+ to upstream this change.
+
+Signed-off-by: Gyorgy Szing <Gyorgy.Szing@arm.com>
+Signed-off-by: Imre Kis <imre.kis@arm.com>
+---
+ library/CMakeLists.txt | 77 +++++++++++++++++++++++++++++++-----------
+ 1 file changed, 57 insertions(+), 20 deletions(-)
+
+diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
+index eeda06aee..d79c657fd 100644
+--- a/library/CMakeLists.txt
++++ b/library/CMakeLists.txt
+@@ -2,6 +2,8 @@ option(USE_STATIC_MBEDTLS_LIBRARY "Build Mbed TLS static library." ON)
+ option(USE_SHARED_MBEDTLS_LIBRARY "Build Mbed TLS shared library." OFF)
+ option(LINK_WITH_PTHREAD "Explicitly link Mbed TLS library to pthread." OFF)
+ option(LINK_WITH_TRUSTED_STORAGE "Explicitly link Mbed TLS library to trusted_storage." OFF)
++option(BUIILD_X509 "Build x509 library too." ON)
++option(BUILD_TLS "Build TLS library too" OFF)
+
+ # Set the project root directory if it's not already defined, as may happen if
+ # the library folder is included directly by a parent project, without
+@@ -255,7 +257,15 @@ if (USE_STATIC_MBEDTLS_LIBRARY)
+ set(mbedcrypto_static_target ${mbedcrypto_target})
+ endif()
+
+-set(target_libraries ${mbedcrypto_target} ${mbedx509_target} ${mbedtls_target})
++set(target_libraries ${mbedcrypto_target})
++
++if (BUIILD_X509)
++ list(APPEND target_libraries ${mbedx509_target})
++endif()
++
++if (BUILD_TLS)
++ list(APPEND target_libraries ${mbedtls_target})
++endif()
+
+ if(USE_STATIC_MBEDTLS_LIBRARY AND USE_SHARED_MBEDTLS_LIBRARY)
+ string(APPEND mbedtls_static_target "_static")
+@@ -263,9 +273,15 @@ if(USE_STATIC_MBEDTLS_LIBRARY AND USE_SHARED_MBEDTLS_LIBRARY)
+ string(APPEND mbedcrypto_static_target "_static")
+
+ list(APPEND target_libraries
+- ${mbedcrypto_static_target}
+- ${mbedx509_static_target}
+- ${mbedtls_static_target})
++ ${mbedcrypto_static_target})
++
++ if (BUIILD_X509 OR BUIILD_TLS)
++ list(APPEND target_libraries ${mbedx509_static_target})
++ endif()
++
++ if (BUILD_TLS)
++ list(APPEND target_libraries ${mbedtls_static_target})
++ endif()
+ endif()
+
+ set(p256m_target "${MBEDTLS_TARGET_PREFIX}p256m")
+@@ -284,13 +300,17 @@ if(USE_STATIC_MBEDTLS_LIBRARY)
+ target_link_libraries(${mbedcrypto_static_target} PUBLIC ${p256m_target})
+ endif()
+
+- add_library(${mbedx509_static_target} STATIC ${src_x509})
+- set_target_properties(${mbedx509_static_target} PROPERTIES OUTPUT_NAME mbedx509)
+- target_link_libraries(${mbedx509_static_target} PUBLIC ${libs} ${mbedcrypto_static_target})
++ if (BUIILD_X509 OR BUIILD_TLS)
++ add_library(${mbedx509_static_target} STATIC ${src_x509})
++ set_target_properties(${mbedx509_static_target} PROPERTIES OUTPUT_NAME mbedx509)
++ target_link_libraries(${mbedx509_static_target} PUBLIC ${libs} ${mbedcrypto_static_target})
++ endif()
+
+- add_library(${mbedtls_static_target} STATIC ${src_tls})
+- set_target_properties(${mbedtls_static_target} PROPERTIES OUTPUT_NAME mbedtls)
+- target_link_libraries(${mbedtls_static_target} PUBLIC ${libs} ${mbedx509_static_target})
++ if (BUILD_TLS)
++ add_library(${mbedtls_static_target} STATIC ${src_tls})
++ set_target_properties(${mbedtls_static_target} PROPERTIES OUTPUT_NAME mbedtls)
++ target_link_libraries(${mbedtls_static_target} PUBLIC ${libs} ${mbedx509_static_target})
++ endif()
+ endif(USE_STATIC_MBEDTLS_LIBRARY)
+
+ if(USE_SHARED_MBEDTLS_LIBRARY)
+@@ -306,14 +326,16 @@ if(USE_SHARED_MBEDTLS_LIBRARY)
+ if(TARGET ${p256m_target})
+ target_link_libraries(${mbedcrypto_target} PUBLIC ${p256m_target})
+ endif()
+-
+- add_library(${mbedx509_target} SHARED ${src_x509})
+- set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.5.1 SOVERSION 6)
+- target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
+-
+- add_library(${mbedtls_target} SHARED ${src_tls})
+- set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.5.1 SOVERSION 20)
+- target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
++ if (BUIILD_X509 OR BUILD_TLS)
++ add_library(${mbedx509_target} SHARED ${src_x509})
++ set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.5.1 SOVERSION 6)
++ target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
++ endif()
++ if (BUILD_TLS)
++ add_library(${mbedtls_target} SHARED ${src_tls})
++ set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.5.1 SOVERSION 20)
++ target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
++ endif()
+ endif(USE_SHARED_MBEDTLS_LIBRARY)
+
+ foreach(target IN LISTS target_libraries)
+@@ -349,7 +371,22 @@ endforeach(target)
+
+ set(lib_target "${MBEDTLS_TARGET_PREFIX}lib")
+
+-add_custom_target(${lib_target} DEPENDS ${mbedcrypto_target} ${mbedx509_target} ${mbedtls_target})
++add_custom_target(${lib_target} DEPENDS ${mbedcrypto_target})
++
++if(BUIILD_X509 OR BUIILD_TLS)
++ add_dependencies(${lib_target} ${mbedx509_target})
++endif()
++
++if(BUIILD_TLS)
++ add_dependencies(${lib_target} ${mbedtls_target})
++endif()
++
+ if(USE_STATIC_MBEDTLS_LIBRARY AND USE_SHARED_MBEDTLS_LIBRARY)
+- add_dependencies(${lib_target} ${mbedcrypto_static_target} ${mbedx509_static_target} ${mbedtls_static_target})
++ add_dependencies(${lib_target} ${mbedcrypto_static_target})
++ if(BUIILD_X509 OR BUIILD_TLS)
++ add_dependencies(${lib_target} ${mbedx509_static_target})
++ endif()
++ if(BUIILD_TLS)
++ add_dependencies(${lib_target} ${mbedtls_static_target})
++ endif()
+ endif()
+--
+2.34.1
+
diff --git a/external/MbedTLS/MbedTLS.cmake b/external/MbedTLS/MbedTLS.cmake
index 3cbaed152..fd83d0113 100644
--- a/external/MbedTLS/MbedTLS.cmake
+++ b/external/MbedTLS/MbedTLS.cmake
@@ -1,96 +1,71 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-# Determine the number of processes to run while running parallel builds.
-# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
-if(NOT DEFINED PROCESSOR_COUNT)
- include(ProcessorCount)
- ProcessorCount(PROCESSOR_COUNT)
- set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
-endif()
-
-set(MBEDTLS_URL "https://github.com/ARMmbed/mbedtls.git" CACHE STRING "Mbed TLS repository URL")
-set(MBEDTLS_REFSPEC "mbedtls-3.0.0" CACHE STRING "Mbed TLS git refspec")
-set(MBEDTLS_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/mbedtls_install" CACHE PATH "Mbed TLS installation directory")
-set(MBEDTLS_PACKAGE_PATH "${MBEDTLS_INSTALL_PATH}/lib/mbedtls/cmake" CACHE PATH "Mbed TLS CMake package directory")
-
-include(FetchContent)
+set(MBEDTLS_URL "https://github.com/Mbed-TLS/mbedtls.git"
+ CACHE STRING "Mbed TLS repository URL")
+set(MBEDTLS_REFSPEC "mbedtls-3.5.1"
+ CACHE STRING "Mbed TLS git refspec")
+set(MBEDTLS_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/mbedtls-src"
+ CACHE PATH "MbedTLS source directory")
+set(MBEDTLS_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/mbedtls_install"
+ CACHE PATH "Mbed TLS installation directory")
+set(MBEDTLS_BUILD_TYPE "Release" CACHE STRING "Mbed TLS build type")
-# Checking git
-find_program(GIT_COMMAND "git")
-if (NOT GIT_COMMAND)
- message(FATAL_ERROR "Please install git")
-endif()
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
-# Fetching Mbed TLS
-FetchContent_Declare(
- mbedtls
+# Mbed TLS has a custom config script that must be ran before invoking CMake.
+# This script configures which components of the project will get built, in our
+# use case only mbedcrypto is necessary. LazyFetch has a PATCH_COMMAND option
+# that was intended to be used for patching the repo after fetch, but before
+# running CMake. However, it can be "misused" in this case to run the Mbed TLS
+# config script.
+set(GIT_OPTIONS
GIT_REPOSITORY ${MBEDTLS_URL}
GIT_TAG ${MBEDTLS_REFSPEC}
- GIT_SHALLOW TRUE
+ GIT_SHALLOW FALSE
+ PATCH_COMMAND
+ git stash
+ COMMAND git branch -f bf-am
+ COMMAND git am ${CMAKE_CURRENT_LIST_DIR}/0001-Add-capability-to-selectively-build-libraries.patch
+ COMMAND git reset bf-am
+ COMMAND ${Python3_EXECUTABLE} scripts/config.py crypto
)
-# FetchContent_GetProperties exports mbedtls_SOURCE_DIR and mbedtls_BINARY_DIR variables
-FetchContent_GetProperties(mbedtls)
-if(NOT mbedtls_POPULATED)
- message(STATUS "Fetching Mbed TLS")
- FetchContent_Populate(mbedtls)
-endif()
-
-# Convert the include path list to a string. Needed to make parameter passing to
-# Mbed TLS build work fine.
-string(REPLACE ";" "\\;" MBEDTLS_EXTRA_INCLUDES "${MBEDTLS_EXTRA_INCLUDES}")
-
-find_package(Python3 COMPONENTS Interpreter)
-if (NOT Python3_Interpreter_FOUND)
- message(FATAL_ERROR "Python 3 interpreter not found.")
+# Only pass libc settings to Mbed TLS if needed. For environments where the standard
+# library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+ include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
+ # Save libc settings
+ save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+ # Translate libc settings to CMake code fragment. Will be inserted into
+ # mbedtls-init-cache.cmake.in when LazyFetch configures the file.
+ translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+ unset_saved_properties(LIBC)
endif()
-#Configure Mbed TLS to build only mbedcrypto lib
-execute_process(COMMAND ${Python3_EXECUTABLE} scripts/config.py crypto WORKING_DIRECTORY ${mbedtls_SOURCE_DIR})
-
-# Advertise Mbed TLS as the provider of the psa crypto API
-set(PSA_CRYPTO_API_INCLUDE "${MBEDTLS_INSTALL_PATH}/include" CACHE STRING "PSA Crypto API include path")
-
-#Configure the library
-execute_process(COMMAND
- ${CMAKE_COMMAND}
- -DENABLE_PROGRAMS=OFF
- -DENABLE_TESTING=OFF
- -DUNSAFE_BUILD=ON
- -DCMAKE_INSTALL_PREFIX=${MBEDTLS_INSTALL_PATH}
- -DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
- -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY
- -DEXTERNAL_DEFINITIONS=-DMBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}"
- -DEXTERNAL_INCLUDE_PATHS=${MBEDTLS_EXTRA_INCLUDES}
- -GUnix\ Makefiles
- ${mbedtls_SOURCE_DIR}
- WORKING_DIRECTORY
- ${mbedtls_BINARY_DIR}
- RESULT_VARIABLE _exec_error
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME MbedTLS
+ FETCH_OPTIONS ${GIT_OPTIONS}
+ INSTALL_DIR ${MBEDTLS_INSTALL_DIR}
+ PACKAGE_DIR ${MBEDTLS_INSTALL_DIR}
+ CACHE_FILE "${TS_ROOT}/external/MbedTLS/mbedtls-init-cache.cmake.in"
+ SOURCE_DIR "${MBEDTLS_SOURCE_DIR}"
)
+unset(_cmake_fragment)
-if (_exec_error)
- message(FATAL_ERROR "Configuration step of Mbed TLS failed with ${_exec_error}.")
-endif()
-
-#TODO: add dependency to generated project on this file!
-#TODO: add custom target to rebuild Mbed TLS
-
-#Build the library
-execute_process(COMMAND
- ${CMAKE_COMMAND} --build ${mbedtls_BINARY_DIR} --parallel ${PROCESSOR_COUNT} --target install
- RESULT_VARIABLE _exec_error
- )
-if (_exec_error)
- message(FATAL_ERROR "Build step of Mbed TLS failed with ${_exec_error}.")
+# Link the libraries created by Mbed TLS to libc if needed. For environments where the standard
+# library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+ foreach(_mbedtls_tgt IN ITEMS "MbedTLS::mbedcrypto")
+ target_link_libraries(${_mbedtls_tgt} INTERFACE stdlib::c)
+ endforeach()
+ unset(_mbedtls_tgt)
endif()
-#Create an imported target to have clean abstraction in the build-system.
-add_library(mbedcrypto STATIC IMPORTED)
-set_property(TARGET mbedcrypto PROPERTY IMPORTED_LOCATION "${MBEDTLS_INSTALL_PATH}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}mbedcrypto${CMAKE_STATIC_LIBRARY_SUFFIX}")
-set_property(TARGET mbedcrypto PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INSTALL_PATH}/include")
+# Advertise Mbed TLS as the provider of the PSA Crypto API
+set(PSA_CRYPTO_API_INCLUDE "${MBEDTLS_INSTALL_DIR}/include"
+ CACHE STRING "PSA Crypto API include path")
diff --git a/components/service/crypto/client/cpp/config_mbedtls_user.h b/external/MbedTLS/config/crypto_posix.h
index 7b3134e79..eaec37e8e 100644
--- a/components/service/crypto/client/cpp/config_mbedtls_user.h
+++ b/external/MbedTLS/config/crypto_posix.h
@@ -1,16 +1,15 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef CONFIG_MBEDTLS_USER_H
-#define CONFIG_MBEDTLS_USER_H
+#ifndef CONFIG_CRYPTO_POSIX_H
+#define CONFIG_CRYPTO_POSIX_H
-/* Mbed TLS configuration for using libmbedcrypto in
- * a Posix environment. Supported crypto operations
- * are configured separately via the PSA crypto build
- * interface (PSA_WANT_xxx).
+/*
+ * Mbed TLS configuration for using libmbedcrypto in
+ * a Posix environment (normal world demo and test applications).
*/
#define MBEDTLS_PSA_CRYPTO_CONFIG
#define MBEDTLS_NO_UDBL_DIVISION
@@ -25,4 +24,4 @@
#undef MBEDTLS_PSA_ITS_FILE_C
#undef MBEDTLS_TIMING_C
-#endif /* CONFIG_MBEDTLS_USER_H */
+#endif /* CONFIG_CRYPTO_POSIX_H */
diff --git a/external/MbedTLS/config/libmbed_only.h b/external/MbedTLS/config/libmbed_only.h
new file mode 100644
index 000000000..0ec4f1258
--- /dev/null
+++ b/external/MbedTLS/config/libmbed_only.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONFIG_LIBMBED_ONLY_H
+#define CONFIG_LIBMBED_ONLY_H
+
+#define MBEDTLS_PSA_CRYPTO_CONFIG
+#define MBEDTLS_NO_UDBL_DIVISION
+#undef MBEDTLS_HAVE_TIME
+#undef MBEDTLS_HAVE_TIME_DATE
+#undef MBEDTLS_FS_IO
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#undef MBEDTLS_SELF_TEST
+#undef MBEDTLS_PLATFORM_C
+#undef MBEDTLS_PSA_ITS_FILE_C
+#undef MBEDTLS_TIMING_C
+#undef MBEDTLS_AESNI_C
+#undef MBEDTLS_AESCE_C
+#undef MBEDTLS_PADLOCK_C
+
+#endif /* CONFIG_LIBMBED_ONLY_H */
diff --git a/external/MbedTLS/config/libmbedx509.h b/external/MbedTLS/config/libmbedx509.h
new file mode 100644
index 000000000..b369d2bcd
--- /dev/null
+++ b/external/MbedTLS/config/libmbedx509.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONFIG_LIBMBEDX509_H
+#define CONFIG_LIBMBEDX509_H
+
+/*
+ * MbedTLS configuration for building libmbedcrypto and libx509 to act as a backend
+ * for the crypto service provider running in an isolated secure processing environment.
+ */
+#define MBEDTLS_PSA_CRYPTO_CONFIG
+#define MBEDTLS_NO_UDBL_DIVISION
+#undef MBEDTLS_HAVE_TIME
+#undef MBEDTLS_HAVE_TIME_DATE
+#undef MBEDTLS_FS_IO
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#undef MBEDTLS_SELF_TEST
+#undef MBEDTLS_PLATFORM_C
+#undef MBEDTLS_PSA_ITS_FILE_C
+#undef MBEDTLS_TIMING_C
+#undef MBEDTLS_AESNI_C
+#undef MBEDTLS_AESCE_C
+#undef MBEDTLS_PADLOCK_C
+
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_X509_USE_C
+#define MBEDTLS_X509_CRL_PARSE_C
+#define MBEDTLS_X509_CRT_PARSE_C
+#define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_OID_C
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_PKCS7_C
+
+#endif /* CONFIG_LIBMBEDX509_H */
diff --git a/external/MbedTLS/config/x509_only.h b/external/MbedTLS/config/x509_only.h
new file mode 100644
index 000000000..5c615fadd
--- /dev/null
+++ b/external/MbedTLS/config/x509_only.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONFIG_X509_ONLY_H
+#define CONFIG_X509_ONLY_H
+
+#undef MBEDTLS_LMS_C
+#undef MBEDTLS_HAVE_TIME
+#undef MBEDTLS_HAVE_TIME_DATE
+#undef MBEDTLS_FS_IO
+#undef MBEDTLS_SELF_TEST
+#undef MBEDTLS_AESNI_C
+#undef MBEDTLS_AESCE_C
+#undef MBEDTLS_PADLOCK_C
+#undef MBEDTLS_PLATFORM_C
+#undef MBEDTLS_PSA_CRYPTO_STORAGE_C
+#undef MBEDTLS_PSA_ITS_FILE_C
+#undef MBEDTLS_TIMING_C
+
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_X509_USE_C
+#define MBEDTLS_X509_CRL_PARSE_C
+#define MBEDTLS_X509_CRT_PARSE_C
+#define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_OID_C
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_PKCS7_C
+
+#endif /* CONFIG_X509_ONLY_H */
diff --git a/external/MbedTLS/mbedtls-init-cache.cmake.in b/external/MbedTLS/mbedtls-init-cache.cmake.in
new file mode 100644
index 000000000..c60bbf2a5
--- /dev/null
+++ b/external/MbedTLS/mbedtls-init-cache.cmake.in
@@ -0,0 +1,24 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX @BUILD_INSTALL_DIR@ CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE @TS_EXTERNAL_LIB_TOOLCHAIN_FILE@ CACHE STRING "")
+
+set(ENABLE_PROGRAMS Off CACHE BOOL "")
+set(ENABLE_TESTING Off CACHE BOOL "")
+set(UNSAFE_BUILD On CACHE BOOL "")
+set(EXTERNAL_DEFINITIONS -DMBEDTLS_USER_CONFIG_FILE="@MBEDTLS_USER_CONFIG_FILE@" CACHE STRING "")
+set(EXTERNAL_INCLUDE_PATHS @MBEDTLS_EXTRA_INCLUDES@ CACHE STRING "")
+
+set(Python3_EXECUTABLE "@Python3_EXECUTABLE@" CACHE PATH "Location of python3 executable")
+
+string(TOUPPER @CMAKE_CROSSCOMPILING@ CMAKE_CROSSCOMPILING) # CMake expects TRUE
+if (CMAKE_CROSSCOMPILING)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
+endif()
+
+@_cmake_fragment@
diff --git a/external/Spdevkit/FindSpdevkit.cmake b/external/Spdevkit/FindSpdevkit.cmake
index dc81cbc38..e69de29bb 100644
--- a/external/Spdevkit/FindSpdevkit.cmake
+++ b/external/Spdevkit/FindSpdevkit.cmake
@@ -1,179 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-#[===[.rst:
- Abstraction to interface to SP DEV KIT.
- ---------------------------------------
-
- SP DEV KIT is a component generated by the OP-TEE OS build and defines the
- FF-A SP interface for the OS to SPs.
-
- This file provides the following functionality:
- - creates a static library to easy building the SP side component of the
- SP DEV KIT. This library will be properly configured with transitive
- dependencies to apply the needed compiler configurations to the
- target linking against it.
- - defines a function to allow configuration of the linking phase of the
- executable target. (See: :command:`sp_dev_kit_configure_linking`)
-
- Inputs:
- ``SP_DEV_KIT_DIR``
- A cmake or environment variable specifying the location of the SP DEV KIT.
- This is mandatory.
-
- ``SP_DEV_KIT_INC_DIR``
- The SP DEV KIT depends on some header files living in the SP. This variable
- must be set to an include path giving access to these headers.
-
- Outputs:
- :command:sp_dev_kit_configure_linking()
-
- :variable:`SP_DEV_KIT_LIBRARIES`
-
-#]===]
-
-# Store SP DEV KIT location to cache.
-# If a cmake variable exist, use it as is.
-# If not, try to copy over the value from the environment.
-if(NOT DEFINED SP_DEV_KIT_DIR AND NOT DEFINED ENV{SP_DEV_KIT_DIR})
- message(FATAL_ERROR "'SP_DEV_KIT_DIR' is not defined.")
-endif()
-set(SP_DEV_KIT_DIR $ENV{SP_DEV_KIT_DIR} CACHE STRING "SP dev kit from original OP-TEE build system")
-
-if (DEFINED ENV{SP_DEV_KIT_DIR} AND NOT SP_DEV_KIT_DIR STREQUAL "$ENV{SP_DEV_KIT_DIR}")
- message(WARNING "Suspicious settings: the value of SP_DEV_KIT_DIR in the environment is not matching cmakes settings!")
-endif()
-
-# Find the directories inside SP DEV KIT. This gives more flexibility than when using static settings.
-find_path (SP_DEV_KIT_SRC_DIR
- NAMES
- sp_header.c
- PATHS
- ${SP_DEV_KIT_DIR}
- PATH_SUFFIXES
- "src"
- NO_DEFAULT_PATH
- REQUIRED
- DOC
- "SP DEV KIT source directory"
- )
-
-find_path (SP_DEV_KIT_INCLUDE_DIR
- NAMES
- ffa.h atomic.h compiler.h
- PATHS
- ${SP_DEV_KIT_DIR}
- PATH_SUFFIXES
- "include"
- NO_DEFAULT_PATH
- REQUIRED
- DOC
- "SP DEV KIT include directory"
- )
-
-find_path (SP_DEV_KIT_LIB_DIR
- NAMES
- ${CMAKE_STATIC_LIBRARY_PREFIX}utils${CMAKE_STATIC_LIBRARY_SUFFIX} libutils.a utils.a utils.lib libutils.link_libraries
- PATHS
- ${SP_DEV_KIT_DIR}
- PATH_SUFFIXES
- "lib"
- NO_DEFAULT_PATH
- REQUIRED
- DOC
- "SP DEV KIT library directory"
- )
-
-#[===[.rst:
-.. cmake:variable:: SP_DEV_KIT_LIBRARIES
-
- List of libraries forming the SP DEV KIT interface.
-
-#]===]
-
-# Create an imported target for libutils.a
-add_library(spdevkit::libutils STATIC IMPORTED)
-set_target_properties(spdevkit::libutils PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${SP_DEV_KIT_INCLUDE_DIR}"
- INTERFACE_LINK_LIBRARIES "${SP_DEV_KIT_LIB_DIR}/libutils.a"
- IMPORTED_LOCATION "${SP_DEV_KIT_LIB_DIR}/libutils.a"
-)
-list(APPEND SP_DEV_KIT_LIBRARIES spdevkit::libutils)
-
-if (NOT Spdevkit_FIND_COMPONENTS OR "SP_HEADER" IN_LIST Spdevkit_FIND_COMPONENTS)
- if (NOT DEFINED SP_DEV_KIT_INC_DIR)
- message(FATAL_ERROR "Mandatory input variable 'SP_DEV_KIT_INC_DIR' is not defined.")
- endif()
-
- # Define a static library to compile the SP side source files and to
- # capture dependencies (settings).
- add_library(sp_header STATIC
- ${SP_DEV_KIT_SRC_DIR}/sp_assert.c
- ${SP_DEV_KIT_SRC_DIR}/sp_entry.c
- ${SP_DEV_KIT_SRC_DIR}/sp_header.c
- )
-
- target_include_directories(sp_header
- PRIVATE
- ${SP_DEV_KIT_INC_DIR}
- )
-
- target_link_libraries(sp_header PRIVATE spdevkit::libutils)
- add_library(spdevkit::sp_header ALIAS sp_header)
- list(APPEND SP_DEV_KIT_LIBRARIES spdevkit::sp_header)
-endif()
-
-#[===[.rst:
-.. cmake:command:: sp_dev_kit_configure_linking
-
- .. code-block:: cmake
-
- sp_dev_kit_configure_linking(TARGET <executable target> DEFINES <list of pre-processor macros>)
-
- Connect an executable target to SP DEV KIT link requirements:
- - add rules to run the linker command file trough the pre-processor if needed
- - configure the target to use the linker command file
- - link SP DEV KIT libraries to the target
-
- Inputs:
-
- ``TARGET``
- Mandatory. The name of an already defined executable target (add_executable())
-
- ``DEFINES``
- Optional. Macro definitions for the pre-processing step.
-
-#]===]
-function(sp_dev_kit_configure_linking)
- set(options )
- set(oneValueArgs TARGET)
- set(multiValueArgs DEFINES)
- cmake_parse_arguments(MY_PARAMS "${options}" "${oneValueArgs}"
- "${multiValueArgs}" ${ARGN} )
-
- if(NOT DEFINED MY_PARAMS_TARGET)
- message(FATAL_ERROR "sp_dev_kit_configure_linking: mandatory parameter TARGET not defined!")
- endif()
-
- if(NOT DEFINED MY_PARAMS_DEFINES)
- set(MY_PARAMS_DEFINES "")
- endif()
-
- compiler_preprocess_file(
- SRC ${SP_DEV_KIT_DIR}/src/sp.ld.S
- DST ${CMAKE_BINARY_DIR}/sp.ld
- DEFINES ${MY_PARAMS_DEFINES}
- )
-
- add_custom_target(${MY_PARAMS_TARGET}-pplscript DEPENDS ${CMAKE_BINARY_DIR}/sp.ld)
- add_dependencies(${MY_PARAMS_TARGET} ${MY_PARAMS_TARGET}-pplscript)
-
- target_link_options(${MY_PARAMS_TARGET} PRIVATE
- -T${CMAKE_BINARY_DIR}/sp.ld
- )
-endfunction()
-
diff --git a/external/edk2_platforms/morello.cmake b/external/edk2_platforms/morello.cmake
new file mode 100644
index 000000000..768908e85
--- /dev/null
+++ b/external/edk2_platforms/morello.cmake
@@ -0,0 +1,28 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+if (DEFINED ENV{TS_EDK2_PLATFORMS_PATH})
+ # Use externally provided source tree
+ set(EDK2_PLATFORMS_PATH $ENV{TS_EDK2_PLATFORMS_PATH} CACHE PATH "edk2-platforms location" FORCE)
+else()
+ # Otherwise clone the morello edk2-platforms repo
+ set(EDK2_PLATFORMS_URL "https://git.morello-project.org/morello/edk2-platforms.git" CACHE STRING "edk2-platforms repository URL")
+ set(EDK2_PLATFORMS_REFSPEC "morello/master" CACHE STRING "edk2-platforms git refspec")
+ set(EDK2_PLATFORMS_PATH "${CMAKE_CURRENT_BINARY_DIR}/_deps/edk2-platforms-src" CACHE PATH "Location of edk2-platforms source")
+
+ set(GIT_OPTIONS
+ GIT_REPOSITORY ${EDK2_PLATFORMS_URL}
+ GIT_TAG ${EDK2_PLATFORMS_REFSPEC}
+ )
+
+ include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+ LazyFetch_MakeAvailable(
+ DEP_NAME edk2-platforms
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ SOURCE_DIR ${EDK2_PLATFORMS_PATH}
+ )
+endif()
diff --git a/external/firmware_test_builder/FirmwareTestBuilder.cmake b/external/firmware_test_builder/FirmwareTestBuilder.cmake
index 4a4cf08e1..f5450c6ce 100644
--- a/external/firmware_test_builder/FirmwareTestBuilder.cmake
+++ b/external/firmware_test_builder/FirmwareTestBuilder.cmake
@@ -1,34 +1,24 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-include(FetchContent)
set(FIRMWARE_TEST_BUILDER_URL "https://git.trustedfirmware.org/TS/trusted-services.git" CACHE STRING "firmware-test-builder repository URL")
set(FIRMWARE_TEST_BUILDER_REFSPEC "topics/fwtb" CACHE STRING "firmware-test-builder git refspec")
-# Checking git
-find_program(GIT_COMMAND "git")
-if (NOT GIT_COMMAND)
- message(FATAL_ERROR "Please install git")
-endif()
-
-# Fetching firmware-test-builder
-FetchContent_Declare(
- firmware_test_builder
+set(GIT_OPTIONS
GIT_REPOSITORY ${FIRMWARE_TEST_BUILDER_URL}
GIT_TAG ${FIRMWARE_TEST_BUILDER_REFSPEC}
- GIT_SHALLOW TRUE
-)
+ GIT_SHALLOW FALSE)
-FetchContent_GetProperties(firmware_test_builder)
-if(NOT firmware_test_builder_POPULATED)
- message(STATUS "Fetching Firmware Test Builder")
- FetchContent_Populate(firmware_test_builder)
-endif()
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(
+ DEP_NAME firmware_test_builder
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ )
# Appending firmware-test-builder's CMake directory to CMake module path
-list(APPEND CMAKE_MODULE_PATH ${firmware_test_builder_SOURCE_DIR}/cmake) \ No newline at end of file
+list(APPEND CMAKE_MODULE_PATH ${firmware_test_builder_SOURCE_DIR}/cmake)
diff --git a/external/libfdt/fix-strnlen.patch b/external/libfdt/fix-strnlen.patch
new file mode 100644
index 000000000..7a7bb7dee
--- /dev/null
+++ b/external/libfdt/fix-strnlen.patch
@@ -0,0 +1,30 @@
+This patch enables using libfdt's strlen() implementation.
+
+diff --git i/libfdt/libfdt_env.h w/libfdt/libfdt_env.h
+index 73b6d40..3a2d38c 100644
+--- i/libfdt/libfdt_env.h
++++ w/libfdt/libfdt_env.h
+@@ -66,13 +66,6 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
+ #undef CPU_TO_FDT16
+ #undef EXTRACT_BYTE
+
+-#ifdef __APPLE__
+-#include <AvailabilityMacros.h>
+-
+-/* strnlen() is not available on Mac OS < 10.7 */
+-# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
+- MAC_OS_X_VERSION_10_7)
+-
+ #define strnlen fdt_strnlen
+
+ /*
+@@ -88,9 +81,4 @@ static inline size_t fdt_strnlen(const char *string, size_t max_count)
+ return p ? p - string : max_count;
+ }
+
+-#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
+- MAC_OS_X_VERSION_10_7) */
+-
+-#endif /* __APPLE__ */
+-
+ #endif /* LIBFDT_ENV_H */
diff --git a/external/libfdt/libfdt.cmake b/external/libfdt/libfdt.cmake
new file mode 100644
index 000000000..9da9bba95
--- /dev/null
+++ b/external/libfdt/libfdt.cmake
@@ -0,0 +1,57 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Use libfdt path from the environment if defined
+if (DEFINED ENV{TS_LIBFDT_PATH})
+ set(LIBFDT_PATH $ENV{TS_LIBFDT_PATH} CACHE PATH "Location of libfdt" FORCE)
+endif()
+
+# Otherwise clone the dtc repo (which contains libfdt)
+set(DTC_URL "https://github.com/dgibson/dtc" CACHE STRING "dtc repository URL")
+set(DTC_REFSPEC "v1.6.1" CACHE STRING "dtc git refspec")
+set(DTC_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/dtc-src" CACHE PATH "Location of dtc source")
+
+set(GIT_OPTIONS
+ GIT_REPOSITORY ${DTC_URL}
+ GIT_TAG ${DTC_REFSPEC}
+ PATCH_COMMAND git stash COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/fix-strnlen.patch
+)
+
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(
+ DEP_NAME dtc
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ SOURCE_DIR ${DTC_SOURCE_DIR}
+)
+
+find_path(LIBFDT_PATH
+ NAMES fdt.c
+ PATHS ${DTC_SOURCE_DIR}/libfdt
+ NO_DEFAULT_PATH
+ REQUIRED
+ DOC "Location of libfdt"
+)
+
+# Add libfdt source files to the target
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${LIBFDT_PATH}/fdt.c"
+ "${LIBFDT_PATH}/fdt_ro.c"
+ "${LIBFDT_PATH}/fdt_wip.c"
+ "${LIBFDT_PATH}/fdt_sw.c"
+ "${LIBFDT_PATH}/fdt_rw.c"
+ "${LIBFDT_PATH}/fdt_strerror.c"
+ "${LIBFDT_PATH}/fdt_empty_tree.c"
+ "${LIBFDT_PATH}/fdt_addresses.c"
+ "${LIBFDT_PATH}/fdt_overlay.c"
+ "${LIBFDT_PATH}/fdt_check.c"
+)
+
+target_include_directories(${TGT} PRIVATE ${LIBFDT_PATH})
diff --git a/external/nanopb/nanopb-init-cache.cmake.in b/external/nanopb/nanopb-init-cache.cmake.in
new file mode 100644
index 000000000..fb8104d64
--- /dev/null
+++ b/external/nanopb/nanopb-init-cache.cmake.in
@@ -0,0 +1,22 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX @BUILD_INSTALL_DIR@ CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE @TS_EXTERNAL_LIB_TOOLCHAIN_FILE@ CACHE STRING "")
+set(BUILD_SHARED_LIBS Off CACHE BOOL "")
+set(BUILD_STATIC_LIBS On CACHE BOOL "")
+set(nanopb_BUILD_RUNTIME On CACHE BOOL "")
+set(nanopb_BUILD_GENERATOR On CACHE BOOL "")
+set(nanopb_MSVC_STATIC_RUNTIME Off BOOL "")
+set(nanopb_PROTOC_PATH ${CMAKE_SOURCE_DIR}/generator/protoc CACHE STRING "")
+
+string(TOUPPER @CMAKE_CROSSCOMPILING@ CMAKE_CROSSCOMPILING) # CMake expects TRUE
+if (CMAKE_CROSSCOMPILING)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
+endif()
+
+@_cmake_fragment@
diff --git a/external/nanopb/nanopb.cmake b/external/nanopb/nanopb.cmake
index 03e45961c..36465f612 100644
--- a/external/nanopb/nanopb.cmake
+++ b/external/nanopb/nanopb.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -24,22 +24,18 @@ running this module.
#]===]
-# Determine the number of processes to run while running parallel builds.
-# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
-if(NOT DEFINED PROCESSOR_COUNT)
- include(ProcessorCount)
- ProcessorCount(PROCESSOR_COUNT)
- set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
-endif()
-
#### Get the dependency
-set(NANOPB_URL "https://github.com/nanopb/nanopb.git" CACHE STRING "nanopb repository URL")
-set(NANOPB_REFSPEC "nanopb-0.4.2" CACHE STRING "nanopb git refspec")
-set(NANOPB_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/nanopb_install" CACHE PATH "nanopb installation directory")
-set(NANOPB_PACKAGE_PATH "${NANOPB_INSTALL_PATH}/libnanopb/cmake" CACHE PATH "nanopb CMake package directory")
-
-include(FetchContent)
+set(NANOPB_URL "https://github.com/nanopb/nanopb.git"
+ CACHE STRING "nanopb repository URL")
+set(NANOPB_REFSPEC "nanopb-0.4.2"
+ CACHE STRING "nanopb git refspec")
+set(NANOPB_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/nanopb-src"
+ CACHE PATH "nanopb source-code")
+set(NANOPB_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/nanopb_install"
+ CACHE PATH "nanopb installation directory")
+set(NANOPB_BUILD_TYPE "Release"
+ CACHE STRING "nanopb build type")
# Checking git
find_program(GIT_COMMAND "git")
@@ -47,101 +43,45 @@ if (NOT GIT_COMMAND)
message(FATAL_ERROR "Please install git")
endif()
-# Fetching nanopb
-FetchContent_Declare(
- nanopb
+set(GIT_OPTIONS
GIT_REPOSITORY ${NANOPB_URL}
GIT_TAG ${NANOPB_REFSPEC}
- GIT_SHALLOW TRUE
+ GIT_SHALLOW FALSE
#See the .patch file for details on why it is needed.
PATCH_COMMAND git stash
COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/fix-pyhon-name.patch
-)
-
-# FetchContent_GetProperties exports nanopb_SOURCE_DIR and nanopb_BINARY_DIR variables
-FetchContent_GetProperties(nanopb)
-if(NOT nanopb_POPULATED)
- message(STATUS "Fetching nanopb")
- FetchContent_Populate(nanopb)
-endif()
-
-#### Build the runtime and the generator.
-
-# Pass extra include paths to nanopb build uning CFLAGS if needed
-if (NOT "${NANOPB_EXTERNAL_INCLUDE_PATHS}" STREQUAL "")
- string(REPLACE ";" "-I " NANOPB_EXTERNAL_INCLUDE_PATHS "${NANOPB_EXTERNAL_INCLUDE_PATHS}")
- set(_SAVED_CFLAGS $ENV{CFLAGS})
- set(ENV{CFLAGS} "$ENV{CFLAGS} -I ${NANOPB_EXTERNAL_INCLUDE_PATHS}")
+ )
+
+# Only pass libc settings to nanopb if needed. For environments where the standard
+# library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+ include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
+
+ # Save libc settings
+ save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+ # Translate libc settings to cmake code fragment. Will be inserted into
+ # nanopb-init-cache.cmake.in when LazyFetch configures the file.
+ translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+ unset_saved_properties(LIBC)
endif()
-if( NOT CMAKE_CROSSCOMPILING)
- execute_process(COMMAND
- ${CMAKE_COMMAND}
- -DBUILD_SHARED_LIBS=Off
- -DBUILD_STATIC_LIBS=On
- -Dnanopb_BUILD_RUNTIME=On
- -Dnanopb_BUILD_GENERATOR=On
- -Dnanopb_PROTOC_PATH=${nanopb_SOURCE_DIR}/generator/protoc
- -Dnanopb_MSVC_STATIC_RUNTIME=Off
- -DCMAKE_INSTALL_PREFIX=${NANOPB_INSTALL_PATH}
- -DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
- -GUnix\ Makefiles
- ${nanopb_SOURCE_DIR}
- WORKING_DIRECTORY
- ${nanopb_BINARY_DIR}
- RESULT_VARIABLE _exec_error
- )
-else()
- execute_process(COMMAND
- ${CMAKE_COMMAND}
- -DBUILD_SHARED_LIBS=Off
- -DBUILD_STATIC_LIBS=On
- -Dnanopb_BUILD_RUNTIME=On
- -Dnanopb_BUILD_GENERATOR=On
- -Dnanopb_PROTOC_PATH=${nanopb_SOURCE_DIR}/generator/protoc
- -Dnanopb_MSVC_STATIC_RUNTIME=Off
- -DCMAKE_INSTALL_PREFIX=${NANOPB_INSTALL_PATH}
- -DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
- -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY
- -GUnix\ Makefiles
- ${nanopb_SOURCE_DIR}
- WORKING_DIRECTORY
- ${nanopb_BINARY_DIR}
- RESULT_VARIABLE _exec_error
- )
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME nanopb
+ FETCH_OPTIONS ${GIT_OPTIONS}
+ INSTALL_DIR ${NANOPB_INSTALL_DIR}
+ PACKAGE_DIR ${NANOPB_INSTALL_DIR}
+ CACHE_FILE "${TS_ROOT}/external/nanopb/nanopb-init-cache.cmake.in"
+ SOURCE_DIR "${NANOPB_SOURCE_DIR}"
+ )
+unset(_cmake_fragment)
+
+if(TARGET stdlib::c)
+ target_link_libraries(nanopb::protobuf-nanopb-static INTERFACE stdlib::c)
endif()
-if (NOT "${NANOPB_EXTERNAL_INCLUDE_PATHS}" STREQUAL "")
- set($ENV{CFLAGS} ${_SAVED_CFLAGS})
- unset(_SAVED_CFLAGS)
- unset(NANOPB_EXTERNAL_INCLUDE_PATHS)
-endif()
-
-if (_exec_error)
- message(FATAL_ERROR "Configuration step of nanopb runtime failed with ${_exec_error}.")
-endif()
-
-execute_process(COMMAND
- ${CMAKE_COMMAND} --build ${nanopb_BINARY_DIR} --parallel ${PROCESSOR_COUNT} --target install
- RESULT_VARIABLE _exec_error
- )
-if (_exec_error)
- message(FATAL_ERROR "Build step of nanopb runtime failed with ${_exec_error}.")
-endif()
-
-#### Include Nanopb runtime in the build.
-find_package(Nanopb
- PATHS "${NANOPB_INSTALL_PATH}"
- NO_DEFAULT_PATH
- )
-
#### Build access to the protobuf compiler
#TODO: verify protoc dependencies: python3-protobuf
-find_package(Python3 COMPONENTS Interpreter)
-
-if (NOT Python3_Interpreter_FOUND)
- message(FATAL_ERROR "Failed to find python3 interpreter.")
-endif()
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
find_file(NANOPB_GENERATOR_PATH
NAMES nanopb_generator.py
@@ -246,9 +186,12 @@ function(protobuf_generate)
target_include_directories(${PARAMS_TGT} PRIVATE ${_OUT_DIR_BASE})
endif()
+ get_filename_component(NANOPB_GENERATOR_DIR "${NANOPB_GENERATOR_PATH}" DIRECTORY CACHE "Location of nanopb generator.")
#Append a protobuf generator command to the nanopb_generate target.
add_custom_command(OUTPUT "${_OUT_C}" "${_OUT_H}"
- COMMAND ${Python3_EXECUTABLE} ${NANOPB_GENERATOR_PATH}
+ COMMAND
+ ${CMAKE_COMMAND} -E env PYTHONPATH=${NANOPB_GENERATOR_DIR}
+ ${Python3_EXECUTABLE} ${NANOPB_GENERATOR_PATH}
-I ${PARAMS_BASE_DIR}
-D ${_OUT_DIR_BASE}
${_SRC_REL}
@@ -312,4 +255,4 @@ function(protobuf_generate_all)
NAMESPACE ${PARAMS_NAMESPACE}
BASE_DIR ${PARAMS_BASE_DIR})
endforeach()
-endfunction() \ No newline at end of file
+endfunction()
diff --git a/external/nanopb/requirements.txt b/external/nanopb/requirements.txt
index 8121141f0..b0db5ff00 100644
--- a/external/nanopb/requirements.txt
+++ b/external/nanopb/requirements.txt
@@ -1,9 +1,9 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
protobuf==3.15.2
-grpcio-tools==1.32.0
+grpcio-tools==1.43.0
diff --git a/external/newlib/0001-Allow-aarch64-linux-gcc-to-compile-bare-metal-lib.patch b/external/newlib/0001-Allow-aarch64-linux-gcc-to-compile-bare-metal-lib.patch
index bd2b2c157..f87ed5a94 100644
--- a/external/newlib/0001-Allow-aarch64-linux-gcc-to-compile-bare-metal-lib.patch
+++ b/external/newlib/0001-Allow-aarch64-linux-gcc-to-compile-bare-metal-lib.patch
@@ -1,21 +1,22 @@
-From 2844dada7e52547c95fc438a946d69de36998b37 Mon Sep 17 00:00:00 2001
+From 64d4a8a9b59ed79bc78658d7edf1bdd9bc4f084d Mon Sep 17 00:00:00 2001
From: Imre Kis <imre.kis@arm.com>
Date: Tue, 19 Oct 2021 11:48:10 +0200
-Subject: [PATCH] Allow aarch64-linux-gcc to compile bare metal lib
+Subject: [PATCH 1/1] Allow aarch64-linux-gcc to compile bare metal lib
Newlib build system determines the target (i.e. Linux, BSD, bare metal,
-etc.) according to the toolchain triplet so it would require a
-sepearate aarch64-none-elf toolchain to be able to build itself for a
-bare metal target.
+etc.) according to the toolchain triplet. This patch changes the
+configure script to treat the aarch64-linux-gnu and the
+aarch64-linux-musl triplets as bare-metal compilers.
Signed-off-by: Imre Kis <imre.kis@arm.com>
+Signed-off-by: Gyorgy Szing <gyorgy.szing@arm.com>
---
configure | 2 +-
libgloss/aarch64/configure | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/configure b/configure
-index 5db527014..1eb71a806 100755
+index 5db52701..1eb71a80 100755
--- a/configure
+++ b/configure
@@ -3659,7 +3659,7 @@ case "${target}" in
@@ -28,7 +29,7 @@ index 5db527014..1eb71a806 100755
;;
*-*-lynxos*)
diff --git a/libgloss/aarch64/configure b/libgloss/aarch64/configure
-index b45256f3c..a25f9f02c 100755
+index b45256f3..25c9d5f7 100755
--- a/libgloss/aarch64/configure
+++ b/libgloss/aarch64/configure
@@ -2521,7 +2521,7 @@ test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS
@@ -36,10 +37,10 @@ index b45256f3c..a25f9f02c 100755
case "${target}" in
- *-*-elf)
-+ *-*-elf | *-linux-gnu)
++ *-*-elf | *-linux-gnu | *-linux-musl)
objtype=elf-
;;
esac
--
-2.33.1
+2.17.1
diff --git a/external/newlib/0002-Disable-unnecessary-targets.patch b/external/newlib/0002-Disable-unnecessary-targets.patch
new file mode 100644
index 000000000..61f181332
--- /dev/null
+++ b/external/newlib/0002-Disable-unnecessary-targets.patch
@@ -0,0 +1,31 @@
+From a8c7c58679126dd4c75538aeedfee0c501df6548 Mon Sep 17 00:00:00 2001
+From: Anton Antonov <anton.antonov@arm.com>
+Date: Mon, 19 Sep 2022 23:37:31 +0200
+Subject: [PATCH 2/2] Disable unnecessary targets
+
+For Trusted Services we require only newlib and libgloss built for
+target. We don't need to build any host tools and we can use a
+cross-compiler only. This patch removes skipping newlib and libgloss for
+this case.
+
+Signed-off-by: Anton Antonov <anton.antonov@arm.com>
+---
+ configure | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/configure b/configure
+index 1eb71a806..dce91609e 100755
+--- a/configure
++++ b/configure
+@@ -2886,7 +2886,7 @@ esac
+
+ # Some are only suitable for cross toolchains.
+ # Remove these if host=target.
+-cross_only="target-libgloss target-newlib target-opcodes"
++cross_only="target-opcodes"
+
+ case $is_cross_compiler in
+ no) skipdirs="${skipdirs} ${cross_only}" ;;
+--
+2.37.0.windows.1
+
diff --git a/external/newlib/newlib.cmake b/external/newlib/newlib.cmake
index d3bd220af..3a0eb23f6 100644
--- a/external/newlib/newlib.cmake
+++ b/external/newlib/newlib.cmake
@@ -1,107 +1,269 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-# Determine the number of processes to run while running parallel builds.
-# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
-if(NOT DEFINED PROCESSOR_COUNT)
- include(ProcessorCount)
- ProcessorCount(PROCESSOR_COUNT)
- set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
+# Add newlib specific porting files to the project.
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
endif()
-set(NEWLIB_URL "https://sourceware.org/git/newlib-cygwin.git" CACHE STRING "newlib repository URL")
-set(NEWLIB_REFSPEC "newlib-4.1.0" CACHE STRING "newlib git refspec")
-set(NEWLIB_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/newlib_install" CACHE PATH "newlib installation directory")
-
-include(FetchContent)
-
-# Checking git
-find_program(GIT_COMMAND "git")
-if (NOT GIT_COMMAND)
- message(FATAL_ERROR "Please install git")
-endif()
+# Adding libc interface
+add_components(TARGET ${TGT}
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ components/common/libc
+)
-# Fetching newlib
-FetchContent_Declare(
- newlib
- GIT_REPOSITORY ${NEWLIB_URL}
- GIT_TAG ${NEWLIB_REFSPEC}
- GIT_SHALLOW TRUE
- PATCH_COMMAND git stash
- COMMAND git am ${CMAKE_CURRENT_LIST_DIR}/0001-Allow-aarch64-linux-gcc-to-compile-bare-metal-lib.patch
- COMMAND git reset HEAD~1
+# Compile TS specific newlib porting files.
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/newlib_init.c"
+ "${CMAKE_CURRENT_LIST_DIR}/newlib_sp_assert.c"
+ "${CMAKE_CURRENT_LIST_DIR}/newlib_sp_heap.c"
)
-# FetchContent_GetProperties exports newlib_SOURCE_DIR and newlib_BINARY_DIR variables
-FetchContent_GetProperties(newlib)
-if(NOT newlib_POPULATED)
- message(STATUS "Fetching newlib")
- FetchContent_Populate(newlib)
-endif()
+# Fetch newlib from external repository
+set(NEWLIB_URL "https://sourceware.org/git/newlib-cygwin.git"
+ CACHE STRING "newlib repository URL")
+set(NEWLIB_REFSPEC "newlib-4.1.0"
+ CACHE STRING "newlib git refspec")
+set(NEWLIB_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/newlib-src"
+ CACHE PATH "newlib source-code location")
+set(NEWLIB_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/newlib_install"
+ CACHE PATH "newlib installation directory")
+# Supported build types: "Release" "Debug" "RelWithDebInfo" "Off"
+# If set to "Off" -DNEWLIB_CFLAGS_TARGET can be used to set compiler
+# switches from the command line.
+set(NEWLIB_BUILD_TYPE "Release" CACHE STRING "newlib build type")
-# Extracing compiler prefix without the trailing hyphen from the C compiler name
+# Extracting compiler prefix without the trailing hyphen from the C compiler name
get_filename_component(COMPILER_PATH ${CMAKE_C_COMPILER} DIRECTORY)
get_filename_component(COMPILER_NAME ${CMAKE_C_COMPILER} NAME)
-string(REGEX REPLACE "([^-]+-[^-]+-[^-]+).*" "\\1" COMPILER_PREFIX ${COMPILER_NAME})
-
-# Newlib configure step
-# CC env var must be unset otherwise configure will assume the cross compiler is the host compiler
-# The configure options are set to minimize code size and memory usage.
-execute_process(COMMAND
- ${CMAKE_COMMAND} -E env --unset=CC PATH=${COMPILER_PATH}:$ENV{PATH} ./configure
- --target=${COMPILER_PREFIX}
- --prefix=${NEWLIB_INSTALL_PATH}
- --enable-newlib-nano-formatted-io
- --enable-newlib-nano-malloc
- --enable-lite-exit
- --enable-newlib-reent-small
- --enable-newlib-global-atexit
- --disable-multilib
- CFLAGS_FOR_TARGET=-fpic
- LDFLAGS_FOR_TARGET=-fpie
- WORKING_DIRECTORY
- ${newlib_SOURCE_DIR}
- RESULT_VARIABLE _newlib_error
-)
+string(REGEX REPLACE "(.*)-[^-]+$" "\\1" COMPILER_PREFIX ${COMPILER_NAME})
-if (_newlib_error)
- message(FATAL_ERROR "Configuration step of newlib failed with ${_newlib_error}.")
-endif()
+find_library(NEWLIB_LIBC_PATH
+ NAMES libc.a c.a libc.lib c.lib
+ PATHS ${NEWLIB_INSTALL_DIR}
+ PATH_SUFFIXES "${COMPILER_PREFIX}/lib"
+ DOC "Location of newlib::libc library."
+ NO_DEFAULT_PATH
+)
+set(NEWLIB_LIBC_PATH ${NEWLIB_LIBC_PATH})
+unset(NEWLIB_LIBC_PATH CACHE)
-# Newlib build step
-execute_process(COMMAND
- ${CMAKE_COMMAND} -E env --unset=CC PATH=${COMPILER_PATH}:$ENV{PATH} make -j${PROCESSOR_COUNT}
- WORKING_DIRECTORY
- ${newlib_SOURCE_DIR}
- RESULT_VARIABLE _newlib_error
+find_library(NEWLIB_LIBNOSYS_PATH
+ NAMES libnosys.a nosys.a nosys.lib nosys.lib
+ PATHS ${NEWLIB_INSTALL_DIR}
+ PATH_SUFFIXES "${COMPILER_PREFIX}/lib"
+ DOC "Location of newlib::libnosys library."
+ NO_DEFAULT_PATH
)
+set(NEWLIB_LIBNOSYS_PATH ${NEWLIB_LIBNOSYS_PATH})
+unset(NEWLIB_LIBNOSYS_PATH CACHE)
-if (_newlib_error)
- message(FATAL_ERROR "Build step of newlib failed with ${_newlib_error}.")
-endif()
+# libc - get compiler specific configuration from GCC
+add_library(c STATIC IMPORTED)
+# We need "freestandig" mode. Ask the compile to do the needed configurations.
+include(${TS_ROOT}/tools/cmake/compiler/GCC.cmake)
+compiler_set_freestanding(TARGET c)
-# Newlib install step
-execute_process(COMMAND
- ${CMAKE_COMMAND} -E env --unset=CC PATH=${COMPILER_PATH}:$ENV{PATH} make install
- WORKING_DIRECTORY
- ${newlib_SOURCE_DIR}
- RESULT_VARIABLE _newlib_error
-)
+if (NOT NEWLIB_LIBC_PATH)
+ # Determine the number of processes to run while running parallel builds.
+ # Pass -DPROCESSOR_COUNT=<n> to cmake to override.
+ if(NOT DEFINED PROCESSOR_COUNT)
+ include(ProcessorCount)
+ ProcessorCount(PROCESSOR_COUNT)
+ set(PROCESSOR_COUNT ${PROCESSOR_COUNT}
+ CACHE STRING "Number of cores to use for parallel builds.")
+ endif()
+
+ # See if the source is available locally
+ find_file(NEWLIB_HEADER_FILE
+ NAMES newlib.h
+ PATHS ${NEWLIB_SOURCE_DIR}
+ PATH_SUFFIXES "newlib/libc/include"
+ NO_DEFAULT_PATH
+ )
+ set(NEWLIB_HEADER_FILE ${NEWLIB_HEADER_FILE})
+ unset(NEWLIB_HEADER_FILE CACHE)
+
+ # Source not found, fetch it.
+ if (NOT NEWLIB_HEADER_FILE)
+ include(FetchContent)
+
+ # Checking git
+ find_program(GIT_COMMAND "git")
+ if (NOT GIT_COMMAND)
+ message(FATAL_ERROR "Please install git")
+ endif()
+
+ # List patch files.
+ file(GLOB _patch_files LIST_DIRECTORIES false "${CMAKE_CURRENT_LIST_DIR}/[0-9]*-[!0-9]*.patch")
+ # Sort items in natural order to ensure patches are amended in the right order.
+ list(SORT _patch_files COMPARE NATURAL)
+ # Convert the list to a string of concatenated quoted list items.
+ string(REPLACE ";" "\" \"" _patch_files "${_patch_files}")
+ set(_patch_files "\"${_patch_files}\"")
+ # Create a shell script patching newlib with the files listed above
+ string(APPEND _patch_script "#!/bin/sh\n"
+ " ${GIT_COMMAND} stash\n"
+ " ${GIT_COMMAND} branch ts-bf-am\n"
+ " ${GIT_COMMAND} am ${_patch_files}\n"
+ " ${GIT_COMMAND} reset ts-bf-am\n"
+ " ${GIT_COMMAND} branch -D ts-bf-am\n"
+ )
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/patch-newlib "${_patch_script}")
+
+ # Fetching newlib
+ FetchContent_Declare(
+ newlib
+ SOURCE_DIR ${NEWLIB_SOURCE_DIR}
+ GIT_REPOSITORY ${NEWLIB_URL}
+ GIT_TAG ${NEWLIB_REFSPEC}
+ GIT_SHALLOW FALSE
+ PATCH_COMMAND sh ${CMAKE_CURRENT_BINARY_DIR}/patch-newlib
+ )
+
+ # FetchContent_GetProperties exports newlib_SOURCE_DIR and newlib_BINARY_DIR variables
+ FetchContent_GetProperties(newlib)
+ # FetchContent_Populate will fail if the source directory is removed since it will try to
+ # do an "update" and not a "populate" action. As a workaround, remove the subbuild directory.
+ # Note: this fix assumes, the default subbuild location is used.
+ file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/_deps/newlib-subbuild")
+
+ if(NOT newlib_POPULATED)
+ message(STATUS "Fetching newlib")
+ FetchContent_Populate(newlib)
+ endif()
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${NEWLIB_SOURCE_DIR})
+ endif()
-if (_newlib_error)
- message(FATAL_ERROR "Install step of newlib failed with ${_newlib_error}.")
+ # Get NEWLIB_EXTRA_PARAMS value from environment
+ set(NEWLIB_EXTRA_PARAMS $ENV{NEWLIB_EXTRA_PARAMS} CACHE STRING "")
+
+ # Split a newlib extra build parameter into a list of parameters
+ set(_extra_params ${NEWLIB_EXTRA_PARAMS})
+ separate_arguments(_extra_params)
+
+ # Transfer libgcc specific settings to newlib, and set position independent compilation
+ string(REPLACE ";" " -I" _more_cflags_target "${LIBGCC_INCLUDE_DIRS}" )
+ set(_more_cflags_target "-fpic -I${_more_cflags_target}")
+
+ string(TOUPPER ${NEWLIB_BUILD_TYPE} UC_NEWLIB_BUILD_TYPE)
+ if ("${UC_NEWLIB_BUILD_TYPE}" STREQUAL "DEBUG")
+ set(_more_cflags_target "${_more_cflags_target} -g -O0")
+ elseif ("${UC_NEWLIB_BUILD_TYPE}" STREQUAL "RELEASE")
+ set(_more_cflags_target "${_more_cflags_target} -O2")
+ elseif ("${UC_NEWLIB_BUILD_TYPE}" STREQUAL "RELWITHDEBINFO")
+ set(_more_cflags_target "${_more_cflags_target} -g -O2")
+ elseif (NOT "${UC_NEWLIB_BUILD_TYPE}" STREQUAL "OFF")
+ message(FATAL_ERROR "unsupported build type to newlib.")
+ endif()
+
+ # Get external extra flags for target from environment.
+ set(NEWLIB_CFLAGS_TARGET $ENV{NEWLIB_CFLAGS_TARGET} CACHE STRING "")
+
+ # Merge our CFLAGS with external CFLAGS
+ if (NOT "${NEWLIB_CFLAGS_TARGET}" STREQUAL "")
+ # Add a space separator if external value is not empty
+ string(APPEND NEWLIB_CFLAGS_TARGET " ")
+ endif()
+ # Concatenate, and override CACHE value
+ set(NEWLIB_CFLAGS_TARGET "${NEWLIB_CFLAGS_TARGET}${_more_cflags_target}" CACHE STRING "" FORCE)
+
+ # Get extra external CFLAGS for host from environment
+ set(NEWLIB_CFLAGS $ENV{NEWLIB_CFLAGS} CACHE STRING "")
+
+ # Newlib is keeping build artifacts in the source directory. If the source is pre-fetched,
+ # intermediate files of previoud build migth be still present.
+ # Run distclean to avoid build errors due to reconfiguration.
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env --unset=CC PATH=${COMPILER_PATH}:$ENV{PATH}
+ make -j${PROCESSOR_COUNT} distclean
+ WORKING_DIRECTORY
+ ${NEWLIB_SOURCE_DIR}
+ RESULT_VARIABLE _newlib_error
+ )
+ #ignore error as distclean-host is failing.
+ #if (_newlib_error)
+ # message(FATAL_ERROR "\"distclean\" step of newlib failed with ${_newlib_error}.")
+ #endif()
+
+ # Newlib configure step
+ # CC env var must be unset otherwise configure will assume the cross compiler is the host
+ # compiler.
+ # The configure options are set to minimize code size and memory usage.
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env --unset=CC PATH=${COMPILER_PATH}:$ENV{PATH} ./configure
+ --target=${COMPILER_PREFIX}
+ --host=${COMPILER_PREFIX}
+ --prefix=${NEWLIB_INSTALL_DIR}
+ --enable-newlib-nano-formatted-io
+ --enable-newlib-nano-malloc
+ --enable-lite-exit
+ --enable-newlib-reent-small
+ --enable-newlib-global-atexit
+ --disable-multilib
+ ${_extra_params}
+ CFLAGS_FOR_TARGET=${NEWLIB_CFLAGS_TARGET}
+ CFLAGS=${NEWLIB_CFLAGS}
+ LDFLAGS_FOR_TARGET=-fpie
+ WORKING_DIRECTORY
+ ${NEWLIB_SOURCE_DIR}
+ RESULT_VARIABLE _newlib_error
+ )
+
+ if (_newlib_error)
+ message(FATAL_ERROR "Configuration step of newlib failed with ${_newlib_error}.")
+ endif()
+
+ # Newlib build step
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env --unset=CC PATH=${COMPILER_PATH}:$ENV{PATH}
+ make -j${PROCESSOR_COUNT}
+ WORKING_DIRECTORY
+ ${NEWLIB_SOURCE_DIR}
+ RESULT_VARIABLE _newlib_error
+ )
+
+ if (_newlib_error)
+ message(FATAL_ERROR "Build step of newlib failed with ${_newlib_error}.")
+ endif()
+
+ # Newlib install step
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env --unset=CC PATH=${COMPILER_PATH}:$ENV{PATH} make install
+ WORKING_DIRECTORY
+ ${NEWLIB_SOURCE_DIR}
+ RESULT_VARIABLE _newlib_error
+ )
+
+ if (_newlib_error)
+ message(FATAL_ERROR "Install step of newlib failed with ${_newlib_error}.")
+ endif()
+
+ set(NEWLIB_LIBC_PATH "${NEWLIB_INSTALL_DIR}/${COMPILER_PREFIX}/lib/libc.a")
+ set(NEWLIB_LIBNOSYS_PATH "${NEWLIB_INSTALL_DIR}/${COMPILER_PREFIX}/lib/libnosys.a")
endif()
-# libc
-add_library(c STATIC IMPORTED)
-set_property(TARGET c PROPERTY IMPORTED_LOCATION "${NEWLIB_INSTALL_PATH}/${COMPILER_PREFIX}/lib/libc.a")
-set_property(TARGET c PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${NEWLIB_INSTALL_PATH}/${COMPILER_PREFIX}/include")
+set_property(DIRECTORY ${CMAKE_SOURCE_DIR}
+ APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${NEWLIB_LIBC_PATH})
+
+# libc - continue configuration
+set_property(TARGET c PROPERTY IMPORTED_LOCATION "${NEWLIB_LIBC_PATH}")
+target_compile_definitions(c INTERFACE ENABLE_CDEFSH_FIX)
+set_property(TARGET c PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${NEWLIB_INSTALL_DIR}/${COMPILER_PREFIX}/include")
+
+# Make standard library available in the build system.
+add_library(stdlib::c ALIAS c)
# libnosys
add_library(nosys STATIC IMPORTED)
-set_property(TARGET nosys PROPERTY IMPORTED_LOCATION "${NEWLIB_INSTALL_PATH}/${COMPILER_PREFIX}/lib/libnosys.a")
-set_property(TARGET nosys PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${NEWLIB_INSTALL_PATH}/${COMPILER_PREFIX}/include")
+set_property(TARGET nosys PROPERTY IMPORTED_LOCATION "${NEWLIB_LIBNOSYS_PATH}")
+set_property(TARGET nosys PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${NEWLIB_INSTALL_DIR}/${COMPILER_PREFIX}/include")
+compiler_set_freestanding(TARGET nosys)
+target_link_libraries(c INTERFACE nosys)
diff --git a/environments/opteesp/newlib_init.c b/external/newlib/newlib_init.c
index 9450a6868..9450a6868 100644
--- a/environments/opteesp/newlib_init.c
+++ b/external/newlib/newlib_init.c
diff --git a/external/newlib/newlib_sp_assert.c b/external/newlib/newlib_sp_assert.c
new file mode 100644
index 000000000..f386bb4f6
--- /dev/null
+++ b/external/newlib/newlib_sp_assert.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "assert_fail_handler.h"
+#include "compiler.h"
+#include <assert.h>
+
+/*
+ * This function implements newlib's assert fail handler function by calling the
+ * generic assert fail handler function that should be implemented by the
+ * environment.
+ */
+void __noreturn __assert_func(const char *file, int line, const char *func,
+ const char *failedexpr)
+{
+ assert_fail_handler(file, line, func, failedexpr);
+ while (1)
+ ;
+}
diff --git a/environments/opteesp/newlib_sp_heap.c b/external/newlib/newlib_sp_heap.c
index 77a288a7d..20b9ce3d9 100644
--- a/environments/opteesp/newlib_sp_heap.c
+++ b/external/newlib/newlib_sp_heap.c
@@ -1,20 +1,19 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*/
#include "compiler.h"
-#include "optee_sp_user_defines.h"
#include <errno.h>
#include <stdint.h>
#include <unistd.h>
/* Allocating heap area */
-#ifndef OPTEE_SP_HEAP_SIZE
-#error "OPTEE_SP_HEAP_SIZE is not defined in SP"
+#ifndef SP_HEAP_SIZE
+#error "SP_HEAP_SIZE is undefined, please define it in the build system"
#endif
-static uint8_t sp_heap[OPTEE_SP_HEAP_SIZE] __aligned(16);
+static uint8_t sp_heap[SP_HEAP_SIZE] __aligned(16);
static uint8_t *program_break = sp_heap;
/**
diff --git a/external/openamp/libmetal-init-cache.cmake.in b/external/openamp/libmetal-init-cache.cmake.in
new file mode 100644
index 000000000..04c25fbde
--- /dev/null
+++ b/external/openamp/libmetal-init-cache.cmake.in
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Linaro. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX "@BUILD_INSTALL_DIR@" CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE "@TS_EXTERNAL_LIB_TOOLCHAIN_FILE@" CACHE STRING "")
+set(BUILD_SHARED_LIBS Off CACHE BOOL "")
+set(BUILD_STATIC_LIBS On CACHE BOOL "")
+
+set(WITH_DOC OFF CACHE BOOL "")
+set(WITH_TESTS OFF CACHE BOOL "")
+set(WITH_EXAMPLES OFF CACHE BOOL "")
+set(WITH_DEFAULT_LOGGER OFF CACHE BOOL "")
+set(MACHINE "template" CACHE STRING "")
+
+@_cmake_fragment@
diff --git a/external/openamp/libmetal.cmake b/external/openamp/libmetal.cmake
new file mode 100644
index 000000000..2457ca859
--- /dev/null
+++ b/external/openamp/libmetal.cmake
@@ -0,0 +1,69 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022 Linaro Limited
+# Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set (LIBMETAL_URL "https://github.com/OpenAMP/libmetal.git"
+ CACHE STRING "libmetal repository URL")
+set (LIBMETAL_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/libmetal_install"
+ CACHE PATH "libmetal installation directory")
+set(LIBMETAL_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/libmetal"
+ CACHE PATH "libmetal source-code")
+set (LIBMETAL_PACKAGE_DIR "${LIBMETAL_INSTALL_DIR}/libmetal/cmake"
+ CACHE PATH "libmetal CMake package directory")
+set (LIBMETAL_REFSPEC "f252f0e007fbfb8b3a52b1d5901250ddac96baad"
+ CACHE STRING "The version of libmetal to use")
+set(LIBMETAL_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/libmetal-build")
+
+set(GIT_OPTIONS
+ GIT_REPOSITORY ${LIBMETAL_URL}
+ GIT_TAG ${LIBMETAL_REFSPEC}
+ GIT_SHALLOW FALSE
+)
+
+if(NOT LIBMETAL_DEBUG)
+ set(LIBMETAL_BUILD_TYPE "Release")
+else()
+ set(LIBMETAL_BUILD_TYPE "Debug")
+endif()
+
+include(FetchContent)
+
+# Checking git
+find_program(GIT_COMMAND "git")
+if (NOT GIT_COMMAND)
+ message(FATAL_ERROR "Please install git")
+endif()
+
+# Only pass libc settings to libmetal if needed. For environments where the
+# standard library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+ include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
+
+ # Save libc settings
+ save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+ # Translate libc settings to cmake code fragment. Will be inserted into
+ # libmetal-init-cache.cmake.in when LazyFetch configures the file.
+ translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+ unset_saved_properties(LIBC)
+endif()
+
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME libmetal
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ INSTALL_DIR "${LIBMETAL_INSTALL_DIR}"
+ CACHE_FILE "${TS_ROOT}/external/openamp/libmetal-init-cache.cmake.in"
+ SOURCE_DIR "${LIBMETAL_SOURCE_DIR}"
+)
+unset(_cmake_fragment)
+
+#Create an imported target to have clean abstraction in the build-system.
+add_library(libmetal STATIC IMPORTED)
+set_property(TARGET libmetal PROPERTY IMPORTED_LOCATION "${LIBMETAL_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}metal${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set_property(TARGET libmetal PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${LIBMETAL_INSTALL_DIR}/include")
+if(TARGET stdlib::c)
+ target_link_libraries(libmetal INTERFACE stdlib::c)
+endif()
diff --git a/external/openamp/openamp-init-cache.cmake.in b/external/openamp/openamp-init-cache.cmake.in
new file mode 100644
index 000000000..302b80511
--- /dev/null
+++ b/external/openamp/openamp-init-cache.cmake.in
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Linaro. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX "@BUILD_INSTALL_DIR@" CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE "@TS_EXTERNAL_LIB_TOOLCHAIN_FILE@" CACHE STRING "")
+set(BUILD_SHARED_LIBS Off CACHE BOOL "")
+set(BUILD_STATIC_LIBS On CACHE BOOL "")
+
+set(LIBMETAL_INCLUDE_DIR "@CMAKE_CURRENT_BINARY_DIR@/libmetal_install/include" CACHE
+ STRING "")
+set(LIBMETAL_LIB "@CMAKE_CURRENT_BINARY_DIR@/libmetal_install/lib" CACHE STRING "")
+set(RPMSG_BUFFER_SIZE "512" CACHE STRING "")
+set(MACHINE "template" CACHE STRING "")
+
+@_cmake_fragment@
diff --git a/external/openamp/openamp.cmake b/external/openamp/openamp.cmake
new file mode 100644
index 000000000..6594826a2
--- /dev/null
+++ b/external/openamp/openamp.cmake
@@ -0,0 +1,69 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022 Linaro Limited
+# Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set (OPENAMP_URL "https://github.com/OpenAMP/open-amp.git"
+ CACHE STRING "OpenAMP repository URL")
+set (OPENAMP_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/openamp_install"
+ CACHE PATH "OpenAMP installation directory")
+set (OPENAMP_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/openamp"
+ CACHE PATH "OpenAMP source code directory")
+set (OPENAMP_PACKAGE_DIR "${OPENAMP_INSTALL_DIR}/openamp/cmake"
+ CACHE PATH "OpenAMP CMake package directory")
+set (OPENAMP_REFSPEC "347397decaa43372fc4d00f965640ebde042966d"
+ CACHE STRING "The version of openamp to use")
+
+set(GIT_OPTIONS_OPENAMP
+ GIT_REPOSITORY ${OPENAMP_URL}
+ GIT_TAG ${OPENAMP_REFSPEC}
+ GIT_SHALLOW FALSE
+)
+
+if(NOT OPENAMP_DEBUG)
+ set(OPENAMP_BUILD_TYPE "Release")
+else()
+ set(OPENAMP_BUILD_TYPE "Debug")
+endif()
+
+# Add libmetal dependency
+include(${TS_ROOT}/external/openamp/libmetal.cmake)
+
+include(FetchContent)
+
+# Checking git
+find_program(GIT_COMMAND "git")
+if (NOT GIT_COMMAND)
+ message(FATAL_ERROR "Please install git")
+endif()
+
+# Only pass libc settings to openamp if needed. For environments where the
+# standard library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+ include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
+
+ # Save libc settings
+ save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+ # Translate libc settings to cmake code fragment. Will be inserted into
+ # libmetal-init-cache.cmake.in when LazyFetch configures the file.
+ translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+ unset_saved_properties(LIBC)
+endif()
+
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME openamp
+ FETCH_OPTIONS "${GIT_OPTIONS_OPENAMP}"
+ INSTALL_DIR "${OPENAMP_INSTALL_DIR}"
+ CACHE_FILE "${TS_ROOT}/external/openamp/openamp-init-cache.cmake.in"
+ SOURCE_DIR "${OPENAMP_SOURCE_DIR}"
+)
+unset(_cmake_fragment)
+
+#Create an imported target to have clean abstraction in the build-system.
+add_library(openamp STATIC IMPORTED)
+set_property(TARGET openamp PROPERTY IMPORTED_LOCATION "${OPENAMP_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}open_amp${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set_property(TARGET openamp PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${OPENAMP_INSTALL_DIR}/include")
+target_link_libraries(openamp INTERFACE libmetal)
diff --git a/external/psa_arch_tests/modify_attest_config.patch b/external/psa_arch_tests/modify_attest_config.patch
deleted file mode 100644
index ebe8c44b4..000000000
--- a/external/psa_arch_tests/modify_attest_config.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h b/api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h
-index 6112ba7..1cdf581 100755
---- a/api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h
-+++ b/api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h
-@@ -60,7 +60,7 @@ typedef uint32_t cfg_id_t;
- #define CRYPTO_VERSION_BETA3
-
- /* Use hardcoded public key */
--#define PLATFORM_OVERRIDE_ATTEST_PK
-+//#define PLATFORM_OVERRIDE_ATTEST_PK
-
- /*
- * Include of PSA defined Header files
diff --git a/external/psa_arch_tests/psa-arch-test-init-cache.cmake.in b/external/psa_arch_tests/psa-arch-test-init-cache.cmake.in
new file mode 100644
index 000000000..5e227a503
--- /dev/null
+++ b/external/psa_arch_tests/psa-arch-test-init-cache.cmake.in
@@ -0,0 +1,26 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_TOOLCHAIN_FILE "@TS_EXTERNAL_LIB_TOOLCHAIN_FILE@" CACHE STRING "")
+
+set(TOOLCHAIN INHERIT CACHE STRING "")
+set(PSA_INCLUDE_PATHS "@PSA_ARCH_TESTS_EXTERNAL_INCLUDE_PATHS@" CACHE STRING "")
+set(SUITE "@TS_ARCH_TEST_SUITE@" CACHE STRING "")
+set(ARCH_TEST_EXTERNAL_DEFS "@PSA_ARCH_TEST_EXTERNAL_DEFS@" CACHE STRING "")
+set(CMAKE_VERBOSE_MAKEFILE OFF CACHE BOOL "")
+set(TARGET "tgt_dev_apis_linux" CACHE STRING "")
+
+# Pass comand line paramter passed to the TS deployment configuration time over to psa-acs build.
+if(NOT "@PSA_TARGET_QCBOR@" STREQUAL "")
+ set(PSA_TARGET_QCBOR "@PSA_TARGET_QCBOR@" CACHE PATH "QCBOR source location for psa-acs.")
+endif()
+
+# Allow setting the QCBOR source-code location for psa-acs in the environment
+# Get the value during psa-acs build from the environment if present.
+if (DEFINED ENV{PSA_TARGET_QCBOR})
+ set(PSA_TARGET_QCBOR $ENV{PSA_TARGET_QCBOR} CACHE PATH "QCBOR source location for psa-acs.")
+endif()
diff --git a/external/psa_arch_tests/psa_arch_tests.cmake b/external/psa_arch_tests/psa_arch_tests.cmake
index e6ab73f7b..29d70eb3a 100644
--- a/external/psa_arch_tests/psa_arch_tests.cmake
+++ b/external/psa_arch_tests/psa_arch_tests.cmake
@@ -1,93 +1,42 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-# Determine the number of processes to run while running parallel builds.
-# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
-if(NOT DEFINED PROCESSOR_COUNT)
- include(ProcessorCount)
- ProcessorCount(PROCESSOR_COUNT)
- set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
-endif()
-
set(PSA_ARCH_TESTS_URL "https://github.com/ARM-software/psa-arch-tests.git" CACHE STRING "psa-arch-tests repository URL")
-set(PSA_ARCH_TESTS_REFSPEC "master" CACHE STRING "psa-arch-tests git refspec")
-set(PSA_ARCH_TESTS_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/psa-arch-tests_install" CACHE PATH "psa-arch-tests installation directory")
-set(PSA_ARCH_TESTS_PACKAGE_PATH "${PSA_ARCH_TESTS_INSTALL_PATH}/libpsa-arch-tests/cmake" CACHE PATH "psa-arch-tests CMake package directory")
-
-include(FetchContent)
-
-# Checking git
-find_program(GIT_COMMAND "git")
-if (NOT GIT_COMMAND)
- message(FATAL_ERROR "Please install git")
-endif()
+set(PSA_ARCH_TESTS_REFSPEC "74dc6646ff594e131a726a5305aba77bac30eceb" CACHE STRING "psa-arch-tests refspec")
+set(PSA_ARCH_TESTS_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/psa_arch_tests-src" CACHE PATH "psa-arch-tests source.")
+set(PSA_ARCH_TESTS_BUILD_TYPE "Release" CACHE STRING "psa-arch-tests build type.")
-# Fetching psa-arch-tests
-FetchContent_Declare(
- psa-arch-tests
+set(GIT_OPTIONS
GIT_REPOSITORY ${PSA_ARCH_TESTS_URL}
GIT_TAG ${PSA_ARCH_TESTS_REFSPEC}
- GIT_SHALLOW TRUE
- PATCH_COMMAND git stash
- COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/modify_attest_config.patch
+ GIT_SHALLOW FALSE
)
-# FetchContent_GetProperties exports psa-arch-tests_SOURCE_DIR and psa-arch-tests_BINARY_DIR variables
-FetchContent_GetProperties(psa-arch-tests)
-if(NOT psa-arch-tests_POPULATED)
- message(STATUS "Fetching psa-arch-tests")
- FetchContent_Populate(psa-arch-tests)
-endif()
-
-# Ensure list of include paths is separated correctly
-string(REPLACE ";" "\\;" PSA_ARCH_TESTS_EXTERNAL_INCLUDE_PATHS "${PSA_ARCH_TESTS_EXTERNAL_INCLUDE_PATHS}")
-
-# Ensure list of defines is separated correctly
-string(REPLACE ";" " " PSA_ARCH_TEST_EXTERNAL_DEFS "${PSA_ARCH_TEST_EXTERNAL_DEFS}")
-
-# Configure the psa-arch-test library
-execute_process(COMMAND
- ${CMAKE_COMMAND}
- -DTOOLCHAIN=INHERIT
- -DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
- -DPSA_INCLUDE_PATHS=${PSA_ARCH_TESTS_EXTERNAL_INCLUDE_PATHS}
- -DSUITE=${TS_ARCH_TEST_SUITE}
- -DARCH_TEST_EXTERNAL_DEFS=${PSA_ARCH_TEST_EXTERNAL_DEFS}
- -DCMAKE_VERBOSE_MAKEFILE=OFF
- -DTARGET=tgt_dev_apis_linux
- -GUnix\ Makefiles
- ${psa-arch-tests_SOURCE_DIR}/api-tests
- WORKING_DIRECTORY
- ${psa-arch-tests_BINARY_DIR}
- RESULT_VARIABLE _exec_error
-)
-
-# Build the library
-if (_exec_error)
- message(FATAL_ERROR "Configuration step of psa-arch-tests runtime failed with ${_exec_error}.")
-endif()
-
-execute_process(COMMAND
- ${CMAKE_COMMAND} --build ${psa-arch-tests_BINARY_DIR} --parallel ${PROCESSOR_COUNT}
- RESULT_VARIABLE _exec_error
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME psa_arch_tests
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ SOURCE_DIR ${PSA_ARCH_TESTS_SOURCE_DIR}
+ SOURCE_SUBDIR "api-tests"
+ CACHE_FILE "${CMAKE_CURRENT_LIST_DIR}/psa-arch-test-init-cache.cmake.in"
)
-if (_exec_error)
- message(FATAL_ERROR "Build step of psa-arch-tests runtime failed with ${_exec_error}.")
-endif()
# Create targets for generated libraries
add_library(test_combine STATIC IMPORTED)
set_property(TARGET test_combine PROPERTY IMPORTED_LOCATION
- "${psa-arch-tests_BINARY_DIR}/dev_apis/${TS_ARCH_TEST_BUILD_SUBDIR}/test_combine${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ "${psa_arch_tests_BINARY_DIR}/dev_apis/${TS_ARCH_TEST_BUILD_SUBDIR}/test_combine${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
+ "${psa_arch_tests_BINARY_DIR}/dev_apis/${TS_ARCH_TEST_BUILD_SUBDIR}/test_combine${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
+ "${PSA_ARCH_TESTS_SOURCE_DIR}/api-tests/val/nspe/val_entry.h")
add_library(val_nspe STATIC IMPORTED)
set_property(TARGET val_nspe PROPERTY IMPORTED_LOCATION
- "${psa-arch-tests_BINARY_DIR}/val/val_nspe${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ "${psa_arch_tests_BINARY_DIR}/val/val_nspe${CMAKE_STATIC_LIBRARY_SUFFIX}")
add_library(pal_nspe STATIC IMPORTED)
set_property(TARGET pal_nspe PROPERTY IMPORTED_LOCATION
- "${psa-arch-tests_BINARY_DIR}/platform/pal_nspe${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ "${psa_arch_tests_BINARY_DIR}/platform/pal_nspe${CMAKE_STATIC_LIBRARY_SUFFIX}")
diff --git a/external/qcbor/0001-Add-3rd-party-settings.patch b/external/qcbor/0001-Add-3rd-party-settings.patch
deleted file mode 100644
index d909e1035..000000000
--- a/external/qcbor/0001-Add-3rd-party-settings.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From daaecfc924678cfd1000c87827bb5b8d4653c8e9 Mon Sep 17 00:00:00 2001
-From: Julian Hall <julian.hall@arm.com>
-Date: Mon, 5 Jul 2021 05:21:00 +0000
-Subject: [PATCH 1/2] Add 3rd party settings
-
-Introduce a way to allow defining include paths and macro
-definitions externally.
----
- CMakeLists.txt | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 8a5bcd0..4e4756d 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -8,6 +8,9 @@ set(CMAKE_C_FLAGS "-pedantic -Wall -O3 -ffunction-sections")
-
- include_directories(inc)
-
-+include_directories(${thirdparty_inc})
-+add_definitions(${thirdparty_def})
-+
- set(SOURCE
- src/ieee754.c
- src/qcbor_decode.c
---
-2.17.1
-
diff --git a/external/qcbor/0001-Introduce-a-way-to-allow-setting-macro-definitions-e.patch b/external/qcbor/0001-Introduce-a-way-to-allow-setting-macro-definitions-e.patch
new file mode 100644
index 000000000..25bd279fa
--- /dev/null
+++ b/external/qcbor/0001-Introduce-a-way-to-allow-setting-macro-definitions-e.patch
@@ -0,0 +1,35 @@
+From c435e364e7fc505e59db2f1ec40bb5f62e591f80 Mon Sep 17 00:00:00 2001
+From: Gyorgy Szing <Gyorgy.Szing@arm.com>
+Date: Wed, 18 May 2022 22:54:47 +0000
+Subject: [PATCH 1/3] Introduce a way to allow setting macro definitions
+ externally.
+
+Signed-off-by: Gyorgy Szing <Gyorgy.Szing@arm.com>
+---
+ CMakeLists.txt | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 8a5bcd0..59dbb54 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -8,12 +8,15 @@ set(CMAKE_C_FLAGS "-pedantic -Wall -O3 -ffunction-sections")
+
+ include_directories(inc)
+
++
++add_definitions(${thirdparty_def})
++
+ set(SOURCE
+ src/ieee754.c
+ src/qcbor_decode.c
+ src/qcbor_encode.c
+ src/qcbor_err_to_str.c
+ src/UsefulBuf.c
+-)
++)
+
+ add_library(qcbor ${SOURCE})
+--
+2.17.1
+
diff --git a/external/qcbor/0002-Add-install-definition.patch b/external/qcbor/0002-Add-install-definition.patch
index f6f0033bc..d23093d81 100644
--- a/external/qcbor/0002-Add-install-definition.patch
+++ b/external/qcbor/0002-Add-install-definition.patch
@@ -1,19 +1,21 @@
-From cb011e7c8ad650bb0dd24930bf19da4a4620e30b Mon Sep 17 00:00:00 2001
+From f118cb26ec8f13e9ff0e0edb1550664d86ecb49a Mon Sep 17 00:00:00 2001
From: Gyorgy Szing <Gyorgy.Szing@arm.com>
Date: Mon, 5 Jul 2021 06:45:47 +0000
-Subject: [PATCH 2/2] Add install definition
+Subject: [PATCH 2/3] Add install definition
Add install() calls to define stable way to access build artifacts.
+
+Signed-off-by: Gyorgy Szing <Gyorgy.Szing@arm.com>
---
CMakeLists.txt | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 4e4756d..b26edce 100644
+index 1b4c95c..c4d91c5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
-@@ -20,3 +20,20 @@ set(SOURCE
- )
+@@ -19,3 +19,20 @@ set(SOURCE
+ )
add_library(qcbor ${SOURCE})
+
@@ -34,5 +36,5 @@ index 4e4756d..b26edce 100644
+ COMPONENT qcbor
+)
--
-2.17.1
+2.35.0.windows.1
diff --git a/external/qcbor/0003-Fix-stop-overriding-C_FLAGS-from-environment.patch b/external/qcbor/0003-Fix-stop-overriding-C_FLAGS-from-environment.patch
new file mode 100644
index 000000000..2951c9855
--- /dev/null
+++ b/external/qcbor/0003-Fix-stop-overriding-C_FLAGS-from-environment.patch
@@ -0,0 +1,31 @@
+From ac33a37507858f6c5ffac8f34541be56cf6b05d1 Mon Sep 17 00:00:00 2001
+From: Gyorgy Szing <Gyorgy.Szing@arm.com>
+Date: Thu, 12 May 2022 21:45:56 +0200
+Subject: [PATCH 3/3] Fix: stop overriding C_FLAGS from environment.
+
+Directly setting CMAKE_C_FLAGS is bad practice as it is overriding
+values taken from C_FLAGS environment variable or from
+CMAKE_C_FLAGS_INIT. The latter is used in toolchain files or in
+initial cache files.
+
+Signed-off-by: Gyorgy Szing <Gyorgy.Szing@arm.com>
+---
+ CMakeLists.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index c4d91c5..a9a5bef 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -4,7 +4,7 @@ project(qcbor
+ LANGUAGES C
+ VERSION 1.0.0)
+
+-set(CMAKE_C_FLAGS "-pedantic -Wall -O3 -ffunction-sections")
++add_compile_options(-pedantic -Wall -O3 -ffunction-sections)
+
+ include_directories(inc)
+
+--
+2.35.0.windows.1
+
diff --git a/external/qcbor/qcbor-init-cache.cmake.in b/external/qcbor/qcbor-init-cache.cmake.in
new file mode 100644
index 000000000..88afecf89
--- /dev/null
+++ b/external/qcbor/qcbor-init-cache.cmake.in
@@ -0,0 +1,17 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX "@BUILD_INSTALL_DIR@" CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE "@TS_EXTERNAL_LIB_TOOLCHAIN_FILE@" CACHE STRING "")
+
+# Determine floating point configuration
+set(TS_NO_FLOAT_HW "@TS_NO_FLOAT_HW@")
+if (TS_NO_FLOAT_HW)
+ set(thirdparty_def "-DQCBOR_DISABLE_FLOAT_HW_USE" CACHE STRING "")
+endif()
+
+@_cmake_fragment@
diff --git a/external/qcbor/qcbor.cmake b/external/qcbor/qcbor.cmake
index 96e5dcbf6..c51ca7140 100644
--- a/external/qcbor/qcbor.cmake
+++ b/external/qcbor/qcbor.cmake
@@ -1,90 +1,57 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# QCBOR is a library for encoding and decoding CBOR objects, as per RFC8949
#-------------------------------------------------------------------------------
-# Determine the number of processes to run while running parallel builds.
-# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
-if(NOT DEFINED PROCESSOR_COUNT)
- include(ProcessorCount)
- ProcessorCount(PROCESSOR_COUNT)
- set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
-endif()
-
-# External component details
set(QCBOR_URL "https://github.com/laurencelundblade/QCBOR.git" CACHE STRING "qcbor repository URL")
-set(QCBOR_REFSPEC "master" CACHE STRING "qcbor git refspec")
-set(QCBOR_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/qcbor_install" CACHE PATH "qcbor installation directory")
-set(QCBOR_PACKAGE_PATH "${QCBOR_INSTALL_PATH}/libqcbor/cmake" CACHE PATH "qcbor CMake package directory")
+set(QCBOR_REFSPEC "v1.0" CACHE STRING "qcbor git refspec")
+set(QCBOR_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/qcbor-src" CACHE PATH "qcbor installation directory")
+set(QCBOR_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/qcbor_install" CACHE PATH "qcbor installation directory")
+set(QCBOR_BUILD_TYPE "Release" CACHE STRING "qcbor build type")
-include(FetchContent)
-
-# Checking git
-find_program(GIT_COMMAND "git")
-if (NOT GIT_COMMAND)
- message(FATAL_ERROR "Please install git")
-endif()
-
-# Fetching qcbor
-FetchContent_Declare(
- qcbor
+set(GIT_OPTIONS
GIT_REPOSITORY ${QCBOR_URL}
GIT_TAG ${QCBOR_REFSPEC}
- GIT_SHALLOW TRUE
+ GIT_SHALLOW FALSE
PATCH_COMMAND git stash
COMMAND git branch -f bf-patch
- COMMAND git am ${CMAKE_CURRENT_LIST_DIR}/0001-Add-3rd-party-settings.patch ${CMAKE_CURRENT_LIST_DIR}/0002-Add-install-definition.patch
+ COMMAND git am ${CMAKE_CURRENT_LIST_DIR}/0001-Introduce-a-way-to-allow-setting-macro-definitions-e.patch
+ ${CMAKE_CURRENT_LIST_DIR}/0002-Add-install-definition.patch
+ ${CMAKE_CURRENT_LIST_DIR}/0003-Fix-stop-overriding-C_FLAGS-from-environment.patch
COMMAND git reset bf-patch
)
-# FetchContent_GetProperties exports qcbor_SOURCE_DIR and qcbor_BINARY_DIR variables
-FetchContent_GetProperties(qcbor)
-if(NOT qcbor_POPULATED)
- message(STATUS "Fetching qcbor")
- FetchContent_Populate(qcbor)
-endif()
-
-# Determine floating point configuration
-if (TS_NO_FLOAT_HW)
- set(_thirdparty_def -DQCBOR_DISABLE_FLOAT_HW_USE)
+# Only pass libc settings to qcbor if needed. For environments where the standard
+# library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+ include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
+
+ # Save libc settings
+ save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+ # Translate libc settings to cmake code fragment. Will be inserted into
+ # qcbor-init-cache.cmake.in when LazyFetch configures the file.
+ translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+ unset_saved_properties(LIBC)
endif()
-# Configure the qcbor library
-if (NOT "${QCBOR_EXTERNAL_INCLUDE_PATHS}" STREQUAL "")
- string(REPLACE ";" "\\;" QCBOR_EXTERNAL_INCLUDE_PATHS "${QCBOR_EXTERNAL_INCLUDE_PATHS}")
- set(QCBOR_EXTRA_OPTION -Dthirdparty_inc=${QCBOR_EXTERNAL_INCLUDE_PATHS})
- unset(QCBOR_EXTERNAL_INCLUDE_PATHS)
-else()
- set(QCBOR_EXTRA_OPTION "")
-endif()
-
-execute_process(COMMAND
- ${CMAKE_COMMAND}
- -DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
- -GUnix\ Makefiles
- -Dthirdparty_def=${_thirdparty_def}
- -DCMAKE_INSTALL_PREFIX=${QCBOR_INSTALL_PATH}
- ${QCBOR_EXTRA_OPTION}
- ${qcbor_SOURCE_DIR}
- WORKING_DIRECTORY
- ${qcbor_BINARY_DIR}
-)
-unset(QCBOR_EXTRA_OPTION)
-
-# Build the library
-execute_process(COMMAND
- ${CMAKE_COMMAND} --build ${qcbor_BINARY_DIR} --parallel ${PROCESSOR_COUNT} --target install
- RESULT_VARIABLE _exec_error
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME qcbor
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ INSTALL_DIR "${QCBOR_INSTALL_DIR}"
+ CACHE_FILE "${CMAKE_CURRENT_LIST_DIR}/qcbor-init-cache.cmake.in"
+ SOURCE_DIR "${QCBOR_SOURCE_DIR}"
)
-if (_exec_error)
- message(FATAL_ERROR "Build step of qcbor failed with ${_exec_error}.")
-endif()
+unset(_cmake_fragment)
# Create an imported target to have clean abstraction in the build-system.
add_library(qcbor STATIC IMPORTED)
-set_property(TARGET qcbor PROPERTY IMPORTED_LOCATION "${QCBOR_INSTALL_PATH}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}qcbor${CMAKE_STATIC_LIBRARY_SUFFIX}")
-set_property(TARGET qcbor PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${QCBOR_INSTALL_PATH}/include")
+set_property(TARGET qcbor PROPERTY IMPORTED_LOCATION "${QCBOR_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}qcbor${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set_property(TARGET qcbor PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${QCBOR_INSTALL_DIR}/include")
+if(TARGET stdlib::c)
+ target_link_libraries(qcbor INTERFACE stdlib::c)
+endif()
+set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${QCBOR_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}qcbor${CMAKE_STATIC_LIBRARY_SUFFIX}")
diff --git a/external/t_cose/0002-Fix-stop-overriding-C_FLAGS-from-environment.patch b/external/t_cose/0002-Fix-stop-overriding-C_FLAGS-from-environment.patch
new file mode 100644
index 000000000..56a42b4db
--- /dev/null
+++ b/external/t_cose/0002-Fix-stop-overriding-C_FLAGS-from-environment.patch
@@ -0,0 +1,31 @@
+From 74f6f0f70f8eb0a073e20008b962a415c6c9c9f9 Mon Sep 17 00:00:00 2001
+From: Gyorgy Szing <Gyorgy.Szing@arm.com>
+Date: Sat, 5 Mar 2022 02:18:06 +0000
+Subject: [PATCH 2/2] Fix stop overriding C_FLAGS from environment.
+
+Directly setting CMAKE_C_FLAGS is bad practice as it is overriding
+values taken from C_FLAGS environment variable or from
+CMAKE_C_FLAGS_INIT. The latter is used in toolchain files or in
+initial cache files.
+
+Signed-off-by: Gyorgy Szing <Gyorgy.Szing@arm.com>
+---
+ CMakeLists.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 343b325..3b43a2e 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -4,7 +4,7 @@ project(t_cose
+ LANGUAGES C
+ VERSION 1.0.1)
+
+-set(CMAKE_C_FLAGS "-pedantic -Wall -O3 -ffunction-sections")
++add_compile_options(-pedantic -Wall -O3 -ffunction-sections)
+
+ include_directories(inc)
+ include_directories(src)
+--
+2.17.1
+
diff --git a/external/t_cose/0002-add-tls3_0_0-compatibility.patch b/external/t_cose/0002-add-tls3_0_0-compatibility.patch
deleted file mode 100644
index 20a7d1311..000000000
--- a/external/t_cose/0002-add-tls3_0_0-compatibility.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-diff --git a/crypto_adapters/t_cose_psa_crypto.c b/crypto_adapters/t_cose_psa_crypto.c
-index 49c5b60..3aa7b58 100644
---- a/crypto_adapters/t_cose_psa_crypto.c
-+++ b/crypto_adapters/t_cose_psa_crypto.c
-@@ -99,7 +99,7 @@ static enum t_cose_err_t psa_status_to_t_cose_error_signing(psa_status_t err)
- err == PSA_ERROR_INVALID_SIGNATURE ? T_COSE_ERR_SIG_VERIFY :
- err == PSA_ERROR_NOT_SUPPORTED ? T_COSE_ERR_UNSUPPORTED_SIGNING_ALG:
- err == PSA_ERROR_INSUFFICIENT_MEMORY ? T_COSE_ERR_INSUFFICIENT_MEMORY :
-- err == PSA_ERROR_TAMPERING_DETECTED ? T_COSE_ERR_TAMPERING_DETECTED :
-+ err == PSA_ERROR_CORRUPTION_DETECTED ? T_COSE_ERR_TAMPERING_DETECTED :
- T_COSE_ERR_SIG_FAIL;
- }
-
-@@ -152,7 +152,7 @@ t_cose_crypto_pub_key_verify(int32_t cose_algorithm_id,
- * Crypto ceases providing backwards compatibility then this code
- * has to be changed to use psa_verify_hash().
- */
-- psa_result = psa_asymmetric_verify(verification_key_psa,
-+ psa_result = psa_verify_hash(verification_key_psa,
- psa_alg_id,
- hash_to_verify.ptr,
- hash_to_verify.len,
-@@ -212,7 +212,7 @@ t_cose_crypto_pub_key_sign(int32_t cose_algorithm_id,
- * providing backwards compatibility then this code has to be
- * changed to use psa_sign_hash().
- */
-- psa_result = psa_asymmetric_sign(signing_key_psa,
-+ psa_result = psa_sign_hash(signing_key_psa,
- psa_alg_id,
- hash_to_sign.ptr,
- hash_to_sign.len,
diff --git a/external/t_cose/t_cose-init-cache.cmake.in b/external/t_cose/t_cose-init-cache.cmake.in
new file mode 100644
index 000000000..abd3eba25
--- /dev/null
+++ b/external/t_cose/t_cose-init-cache.cmake.in
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX "@BUILD_INSTALL_DIR@" CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE "@TS_EXTERNAL_LIB_TOOLCHAIN_FILE@" CACHE STRING "")
+
+set(MBEDTLS On CACHE STRING "")
+
+@_cmake_fragment@
diff --git a/external/t_cose/t_cose.cmake b/external/t_cose/t_cose.cmake
index 660824bdc..32a81e30f 100644
--- a/external/t_cose/t_cose.cmake
+++ b/external/t_cose/t_cose.cmake
@@ -1,90 +1,77 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# t_cose is a library for signing CBOR tokens using COSE_Sign1
#-------------------------------------------------------------------------------
-# Determine the number of processes to run while running parallel builds.
-# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
-if(NOT DEFINED PROCESSOR_COUNT)
- include(ProcessorCount)
- ProcessorCount(PROCESSOR_COUNT)
- set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
-endif()
-
-# External component details
set(T_COSE_URL "https://github.com/laurencelundblade/t_cose.git" CACHE STRING "t_cose repository URL")
-set(T_COSE_REFSPEC "master" CACHE STRING "t_cose git refspec")
-set(T_COSE_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/t_cose_install" CACHE PATH "t_cose installation directory")
-set(T_COSE_PACKAGE_PATH "${T_COSE_INSTALL_PATH}/libt_cose/cmake" CACHE PATH "t_cose CMake package directory")
-
-include(FetchContent)
+set(T_COSE_REFSPEC "fc3a4b2c7196ff582e8242de8bd4a1bc4eec577f" CACHE STRING "t_cose git refspec")
+set(T_COSE_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/t_cose-src" CACHE PATH "t_cose installation directory")
+set(T_COSE_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/t_cose_install" CACHE PATH "t_cose installation directory")
+set(T_COSE_BUILD_TYPE "Release" CACHE STRING "t_cose build type")
-# Checking git
-find_program(GIT_COMMAND "git")
-if (NOT GIT_COMMAND)
- message(FATAL_ERROR "Please install git")
-endif()
-
-# Fetching t_cose
-FetchContent_Declare(
- t_cose
+set(GIT_OPTIONS
GIT_REPOSITORY ${T_COSE_URL}
GIT_TAG ${T_COSE_REFSPEC}
- GIT_SHALLOW TRUE
+ GIT_SHALLOW FALSE
PATCH_COMMAND git stash
+ COMMAND git branch -f bf-patch
COMMAND git am ${CMAKE_CURRENT_LIST_DIR}/0001-add-install-definition.patch
- COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/0002-add-tls3_0_0-compatibility.patch
- COMMAND git reset HEAD~1
-
+ ${CMAKE_CURRENT_LIST_DIR}/0002-Fix-stop-overriding-C_FLAGS-from-environment.patch
+ COMMAND git reset bf-patch
)
-# FetchContent_GetProperties exports t_cose_SOURCE_DIR and t_cose_BINARY_DIR variables
-FetchContent_GetProperties(t_cose)
-if(NOT t_cose_POPULATED)
- message(STATUS "Fetching t_cose")
- FetchContent_Populate(t_cose)
+include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
+
+# Only pass libc settings to t-cose if needed. For environments where the standard
+# library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+ # Save libc settings
+ save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+ # Translate libc settings to cmake code fragment. Will be inserted into
+ # t_cose-init-cache.cmake.in when LazyFetch configures the file.
+ translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+ unset_saved_properties(LIBC)
endif()
# Prepare include paths for dependencies that t_codse has on external components
-get_target_property(_qcbor_inc qcbor INTERFACE_INCLUDE_DIRECTORIES)
-set(_ext_inc_paths
- ${_qcbor_inc}
- ${PSA_CRYPTO_API_INCLUDE})
+save_interface_target_properties(TGT qcbor PREFIX QCBOR)
+translate_interface_target_properties(PREFIX QCBOR RES _cmake_fragment1)
+unset_saved_properties(QCBOR)
+string(APPEND _cmake_fragment "\n${_cmake_fragment1}")
+unset(_cmake_fragment1)
-if (NOT TCOSE_EXTERNAL_INCLUDE_PATHS STREQUAL "")
- list(APPEND _ext_inc_paths "${TCOSE_EXTERNAL_INCLUDE_PATHS}")
- unset(TCOSE_EXTERNAL_INCLUDE_PATHS)
+if (NOT DEFINED PSA_CRYPTO_API_INCLUDE)
+ string(CONCAT _msg "Mandatory parameter PSA_CRYPTO_API_INCLUDE is not defined. Please include a component which"
+ " sets this variable or pass -DPSA_CRYPTO_API_INCLUDE=<path> where <path> is the location of"
+ " PSA API headers.")
+ message(FATAL_ERROR ${_msg} )
endif()
-string(REPLACE ";" "\\;" _ext_inc_paths "${_ext_inc_paths}")
-
-# Configure the t_cose library
-execute_process(COMMAND
-${CMAKE_COMMAND}
- -DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
- -Dthirdparty_inc=${_ext_inc_paths}
- -DCMAKE_INSTALL_PREFIX=${T_COSE_INSTALL_PATH}
- -DMBEDTLS=On
- -GUnix\ Makefiles
- ${t_cose_SOURCE_DIR}
-WORKING_DIRECTORY
- ${t_cose_BINARY_DIR}
-)
+translate_value_as_property(VALUE "${PSA_CRYPTO_API_INCLUDE}"
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ RES _cmake_fragment1)
+string(APPEND _cmake_fragment "\n${_cmake_fragment1}")
+unset(_cmake_fragment1)
-# Build the library
-execute_process(COMMAND
- ${CMAKE_COMMAND} --build ${t_cose_BINARY_DIR} --parallel ${PROCESSOR_COUNT} --target install
- RESULT_VARIABLE _exec_error
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME t_cose
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ INSTALL_DIR ${T_COSE_INSTALL_DIR}
+ CACHE_FILE "${CMAKE_CURRENT_LIST_DIR}/t_cose-init-cache.cmake.in"
+ SOURCE_DIR "${T_COSE_SOURCE_DIR}"
)
-if (_exec_error)
- message(FATAL_ERROR "Build step of t_cose failed with ${_exec_error}.")
-endif()
+unset(_cmake_fragment)
# Create an imported target to have clean abstraction in the build-system.
add_library(t_cose STATIC IMPORTED)
-set_property(TARGET t_cose PROPERTY IMPORTED_LOCATION "${T_COSE_INSTALL_PATH}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}t_cose${CMAKE_STATIC_LIBRARY_SUFFIX}")
-set_property(TARGET t_cose PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${T_COSE_INSTALL_PATH}/include")
+target_link_libraries(t_cose INTERFACE qcbor)
+set_property(TARGET t_cose PROPERTY IMPORTED_LOCATION "${T_COSE_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}t_cose${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set_property(TARGET t_cose PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${T_COSE_INSTALL_DIR}/include")
+if(TARGET stdlib::c)
+ target_link_libraries(t_cose INTERFACE stdlib::c)
+endif()
+set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${T_COSE_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}t_cose${CMAKE_STATIC_LIBRARY_SUFFIX}")
diff --git a/external/tf_a/include/cdefs.h b/external/tf_a/include/cdefs.h
new file mode 100644
index 000000000..e52b60a16
--- /dev/null
+++ b/external/tf_a/include/cdefs.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TF_A_CDEFS_H
+#define TF_A_CDEFS_H
+
+/**
+ * Some tf-a files assume that <cdefs.h> is in the global include path. This
+ * provides an alternative using common/utils/compiler.h.
+ */
+#include <compiler.h>
+
+#endif /* TF_A_CDEFS_H */
diff --git a/external/tf_a/include/common/debug.h b/external/tf_a/include/common/debug.h
new file mode 100644
index 000000000..8f0d068a4
--- /dev/null
+++ b/external/tf_a/include/common/debug.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TF_A_COMMON_DEBUG_H
+#define TF_A_COMMON_DEBUG_H
+
+/**
+ * Overrides the tf-a version to avoid a dependency on the tf-a debug environment.
+ * Some tf-a components rely on debug.h to bring some standard include files. The
+ * following includes provide the missing include files.
+ */
+#include <stdint.h>
+
+/**
+ * Log operations
+ */
+#define ERROR(...)
+#define ERROR_NL()
+
+#define NOTICE(...)
+#define WARN(...)
+
+#define INFO(...)
+
+#define VERBOSE(...)
+
+#endif /* TF_A_COMMON_DEBUG_H */
diff --git a/external/tf_a/include/lib/utils.h b/external/tf_a/include/lib/utils.h
new file mode 100644
index 000000000..c58e1e72b
--- /dev/null
+++ b/external/tf_a/include/lib/utils.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TF_A_LIB_UTILS_H
+#define TF_A_LIB_UTILS_H
+
+#include <stddef.h>
+#include <string.h>
+
+/**
+ * A stub version of the tf-a lib/utils.h
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline void zeromem(void *mem, size_t length)
+{
+ memset(mem, 0, length);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TF_A_LIB_UTILS_H */
diff --git a/external/tf_a/include/plat/common/platform.h b/external/tf_a/include/plat/common/platform.h
new file mode 100644
index 000000000..eecbffa9d
--- /dev/null
+++ b/external/tf_a/include/plat/common/platform.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TF_A_PLAT_COMMON_PLATFORM_H
+#define TF_A_PLAT_COMMON_PLATFORM_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Overrides the tf-a version to map the TF-A platform interface to the TS
+ * platform interface.
+ */
+int plat_get_image_source(
+ unsigned int image_id,
+ uintptr_t *dev_handle,
+ uintptr_t *image_spec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TF_A_PLAT_COMMON_PLATFORM_H */
diff --git a/external/tf_a/include/platform_def.h b/external/tf_a/include/platform_def.h
new file mode 100644
index 000000000..d9ea08b56
--- /dev/null
+++ b/external/tf_a/include/platform_def.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TF_A_PALTFORM_DEF_H
+#define TF_A_PALTFORM_DEF_H
+
+#include <stdbool.h>
+
+/**
+ * Provides a set of defaults for values defined by the platform specific
+ * 'platform_def.h' file. Deployments may override default definitions.
+ */
+
+#ifndef ENABLE_ASSERTIONS
+#define ENABLE_ASSERTIONS true
+#endif
+
+#ifndef MAX_IO_HANDLES
+#define MAX_IO_HANDLES (4)
+#endif
+
+#ifndef MAX_IO_DEVICES
+#define MAX_IO_DEVICES (4)
+#endif
+
+#endif /* TF_A_PALTFORM_DEF_H */
diff --git a/external/tf_a/tf-a.cmake b/external/tf_a/tf-a.cmake
new file mode 100644
index 000000000..a7a28f8f5
--- /dev/null
+++ b/external/tf_a/tf-a.cmake
@@ -0,0 +1,62 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Fetch or use externally provided source tree
+#
+#-------------------------------------------------------------------------------
+if (DEFINED ENV{TS_TFA_PATH})
+ # Use externally provided source tree
+ set(TFA_SOURCE_DIR $ENV{TS_TFA_PATH} CACHE PATH "tf-a location" FORCE)
+else()
+ # Otherwise clone the tf-a repo
+ set(TFA_URL "https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git" CACHE STRING "tf-a repository URL")
+ set(TFA_REFSPEC "v2.7.0" CACHE STRING "tf-a git refspec")
+ set(TFA_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/tf-a-src" CACHE PATH "Location of tf-a source")
+
+ # Checking git
+ find_program(GIT_COMMAND "git")
+ if (NOT GIT_COMMAND)
+ message(FATAL_ERROR "Please install git")
+ endif()
+
+ set(GIT_OPTIONS
+ GIT_REPOSITORY ${TFA_URL}
+ GIT_TAG ${TFA_REFSPEC}
+ GIT_SHALLOW FALSE
+ )
+
+ include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+ LazyFetch_MakeAvailable(
+ DEP_NAME tf-a
+ FETCH_OPTIONS "${GIT_OPTIONS}"
+ SOURCE_DIR ${TFA_SOURCE_DIR}
+ )
+endif()
+
+#-------------------------------------------------------------------------------
+# Add tf-a as an external dependency
+#
+#-------------------------------------------------------------------------------
+function(add_tfa_dependency)
+ set(options )
+ set(oneValueArgs TARGET)
+ cmake_parse_arguments(MY_PARAMS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ if(NOT DEFINED MY_PARAMS_TARGET)
+ message(FATAL_ERROR "add_tf-a: mandatory parameter TARGET not defined!")
+ endif()
+
+ # Provide override include files to enable tf-a components to be compiled outside of
+ # the tf-a build environment.
+ target_include_directories(${MY_PARAMS_TARGET} PRIVATE "${TS_ROOT}/external/tf_a/include")
+
+ # Export tf-a public include files
+ target_include_directories(${MY_PARAMS_TARGET} PRIVATE "${TFA_SOURCE_DIR}/include")
+ target_include_directories(${MY_PARAMS_TARGET} PRIVATE "${TFA_SOURCE_DIR}/include/arch/aarch64")
+
+endfunction() \ No newline at end of file
diff --git a/platform/drivers/arm/juno_trng/juno_trng_adapter.c b/platform/drivers/arm/juno_trng/juno_trng_adapter.c
index 3ad8b0427..69d37ce2b 100644
--- a/platform/drivers/arm/juno_trng/juno_trng_adapter.c
+++ b/platform/drivers/arm/juno_trng/juno_trng_adapter.c
@@ -1,10 +1,12 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <config/interface/config_store.h>
#include <platform/interface/trng.h>
#include <platform/interface/device_region.h>
+#include <psa/error.h>
#include "juno_decl.h"
/*
@@ -38,10 +40,10 @@ static int trng_poll(void *context, unsigned char *output, size_t nbyte, size_t
return status;
}
-int platform_trng_create(struct platform_trng_driver *driver,
- const struct device_region *device_region)
+int platform_trng_create(struct platform_trng_driver *driver, int instance)
{
static const struct platform_trng_iface iface = { .poll = trng_poll };
+ struct device_region device_region;
/*
* Default to leaving the driver in a safe but inoperable state.
@@ -49,15 +51,17 @@ int platform_trng_create(struct platform_trng_driver *driver,
driver->iface = &iface;
driver->context = NULL;
- if (device_region) {
+ if (!config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, "trng",
+ instance, &device_region,
+ sizeof(device_region)))
+ return PSA_STATUS_HARDWARE_FAILURE;
- /*
- * A device region has been provided, possibly from an external configuation.
- */
- juno_trng_set_base_addr(device_region->base_addr);
- }
+ /*
+ * A device region has been provided, possibly from an external configuation.
+ */
+ juno_trng_set_base_addr(device_region.base_addr);
- return 0;
+ return PSA_SUCCESS;
}
void platform_trng_destroy(struct platform_trng_driver *driver)
diff --git a/components/service/discovery/provider/component.cmake b/platform/drivers/arm/mhu_driver/component.cmake
index 85dfa8584..77a5a50b6 100644
--- a/components/service/discovery/provider/component.cmake
+++ b/platform/drivers/arm/mhu_driver/component.cmake
@@ -4,10 +4,9 @@
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
-if (NOT DEFINED TGT)
- message(FATAL_ERROR "mandatory parameter TGT is not defined.")
-endif()
-target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/discovery_provider.c"
- )
+# Add source files for using mhu driver
+target_sources(${TGT}
+ PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/mhu_v2_x.c"
+)
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2.h b/platform/drivers/arm/mhu_driver/mhu_v2.h
new file mode 100644
index 000000000..26b3a5d63
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2.h
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+
+/**
+ * \file mhu_v2_x.h
+ * \brief Driver for Arm MHU v2.0 and v2.1
+ */
+
+#ifndef __MHU_V2_X_H__
+#define __MHU_V2_X_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MHU_2_X_INTR_NR2R_OFF (0x0u)
+#define MHU_2_X_INTR_R2NR_OFF (0x1u)
+#define MHU_2_1_INTR_CHCOMB_OFF (0x2u)
+
+#define MHU_2_X_INTR_NR2R_MASK (0x1u << MHU_2_X_INTR_NR2R_OFF)
+#define MHU_2_X_INTR_R2NR_MASK (0x1u << MHU_2_X_INTR_R2NR_OFF)
+#define MHU_2_1_INTR_CHCOMB_MASK (0x1u << MHU_2_1_INTR_CHCOMB_OFF)
+
+enum mhu_v2_x_frame_t {
+ MHU_V2_X_SENDER_FRAME = 0x0u,
+ MHU_V2_X_RECEIVER_FRAME = 0x1u,
+};
+
+enum mhu_v2_x_supported_revisions {
+ MHU_REV_READ_FROM_HW = 0,
+ MHU_REV_2_0,
+ MHU_REV_2_1,
+};
+
+struct mhu_v2_x_dev_t {
+ uintptr_t base;
+ enum mhu_v2_x_frame_t frame;
+ uint32_t subversion; /*!< Hardware subversion: v2.X */
+ bool is_initialized; /*!< Indicates if the MHU driver
+ * is initialized and enabled
+ */
+};
+
+/**
+ * \brief MHU v2 error enumeration types.
+ */
+enum mhu_v2_x_error_t {
+ MHU_V_2_X_ERR_NONE = 0,
+ MHU_V_2_X_ERR_NOT_INIT = -1,
+ MHU_V_2_X_ERR_ALREADY_INIT = -2,
+ MHU_V_2_X_ERR_UNSUPPORTED_VERSION = -3,
+ MHU_V_2_X_ERR_INVALID_ARG = -4,
+ MHU_V_2_X_ERR_GENERAL = -5
+};
+
+/**
+ * \brief Initializes the driver
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] rev MHU revision (if can't be identified from HW)
+ *
+ * Reads the MHU hardware version
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note MHU revision only has to be specified when versions can't be read
+ * from HW (ARCH_MAJOR_REV reg reads as 0x0).
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+ enum mhu_v2_x_supported_revisions rev);
+
+/**
+ * \brief Returns the number of channels implemented.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Returns the number of channels implemented.
+ *
+ * \return Returns the number of channels implemented.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+uint32_t mhu_v2_x_get_num_channel_implemented(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Sends the value over a channel.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Channel to send the value over.
+ * \param[in] val Value to send.
+ *
+ * Sends the value over a channel.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t val);
+
+/**
+ * \brief Clears the channel after the value is send over it.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Channel to clear.
+ *
+ * Clears the channel after the value is send over it.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel);
+
+/**
+ * \brief Receives the value over a channel.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Channel to receive the value from.
+ * \param[out] value Pointer to variable that will store the value.
+ *
+ * Receives the value over a channel.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value);
+
+/**
+ * \brief Sets bits in the Channel Mask.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's mask to set.
+ * \param[in] mask Mask to be set over a receiver frame.
+ *
+ * Sets bits in the Channel Mask.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * \brief Clears bits in the Channel Mask.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's mask to clear.
+ * \param[in] mask Mask to be clear over a receiver frame.
+ *
+ * Clears bits in the Channel Mask.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * \brief Enables the Channel interrupt.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's interrupt to enable.
+ *
+ * Enables the Channel clear interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_enable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Disables the Channel interrupt.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's interrupt to disable.
+ *
+ * Disables the Channel interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_disable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Cleares the Channel interrupt.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Which channel's interrupt to clear.
+ *
+ * Cleares the Channel interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Initiates a MHU transfer with the handshake signals.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Initiates a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Closes a MHU transfer with the handshake signals.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Closes a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Returns the value of access request signal.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] val Pointer to variable that will store the value.
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_get_access_request(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *val);
+
+/**
+ * \brief Sets the value of access request signal to high.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_set_access_request(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Sets the value of access request signal to low.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_reset_access_request(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Returns the value of access ready signal.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] val Pointer to variable that will store the value.
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_get_access_ready(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *val);
+
+/**
+ * \brief Returns the MHU interrupt status.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * \return Interrupt status register value. Masking is needed for individual
+ * interrupts.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+uint32_t mhu_v2_x_get_interrupt_status(const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Enables MHU interrupts.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask Bit mask for enabling/disabling interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_enable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Disables MHU interrupts.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask Bit mask for enabling/disabling interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_disable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Clears MHU interrupts.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask Bit mask for clearing interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Returns the first channel number whose interrupt bit is high.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] channel Pointer to variable that will have the channel value.
+ *
+ * \return Returns the first channel number whose interrupt bit is high.
+ * \return Returns mhu_v2_x_error_t error code.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_1_get_ch_interrupt_num(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *channel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MHU_V2_X_H__ */
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x.c
new file mode 100644
index 000000000..d7e70efaa
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+#include <stdint.h>
+#include <stdbool.h>
+#include "mhu_v2.h"
+
+#define _MHU_V2_X_MAX_CHANNELS 124
+#define _MHU_V2_1_MAX_CHCOMB_INT 4
+#define ENABLE 0x1
+#define DISABLE 0x0
+#define CLEAR_INTR 0x1
+#define CH_PER_CH_COMB 0x20
+#define SEND_FRAME(p_mhu) ((struct _mhu_v2_x_send_frame_t *)p_mhu)
+#define RECV_FRAME(p_mhu) ((struct _mhu_v2_x_recv_frame_t *)p_mhu)
+
+#define MHU_MAJOR_REV_V2 0x1u
+#define MHU_MINOR_REV_2_0 0x0u
+#define MHU_MINOR_REV_2_1 0x1u
+
+struct _mhu_v2_x_send_ch_window_t {
+ /* Offset: 0x00 (R/ ) Channel Status */
+ volatile uint32_t ch_st;
+ /* Offset: 0x04 (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0x08 (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+ /* Offset: 0x0C ( /W) Channel Set */
+ volatile uint32_t ch_set;
+ /* Offset: 0x10 (R/ ) Channel Interrupt Status (Reserved in 2.0) */
+ volatile uint32_t ch_int_st;
+ /* Offset: 0x14 ( /W) Channel Interrupt Clear (Reserved in 2.0) */
+ volatile uint32_t ch_int_clr;
+ /* Offset: 0x18 (R/W) Channel Interrupt Enable (Reserved in 2.0) */
+ volatile uint32_t ch_int_en;
+ /* Offset: 0x1C (R/ ) Reserved */
+ volatile uint32_t reserved_2;
+};
+
+struct _mhu_v2_x_send_frame_t {
+ /* Offset: 0x000 ( / ) Sender Channel Window 0 -123 */
+ struct _mhu_v2_x_send_ch_window_t send_ch_window[_MHU_V2_X_MAX_CHANNELS];
+ /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+ volatile uint32_t mhu_cfg;
+ /* Offset: 0xF84 (R/W) Response Configuration */
+ volatile uint32_t resp_cfg;
+ /* Offset: 0xF88 (R/W) Access Request */
+ volatile uint32_t access_request;
+ /* Offset: 0xF8C (R/ ) Access Ready */
+ volatile uint32_t access_ready;
+ /* Offset: 0xF90 (R/ ) Interrupt Status */
+ volatile uint32_t int_st;
+ /* Offset: 0xF94 ( /W) Interrupt Clear */
+ volatile uint32_t int_clr;
+ /* Offset: 0xF98 (R/W) Interrupt Enable */
+ volatile uint32_t int_en;
+ /* Offset: 0xF9C (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0xFA0 (R/W) Channel Combined Interrupt Stat (Reserved in 2.0) */
+ volatile uint32_t ch_comb_int_st[_MHU_V2_1_MAX_CHCOMB_INT];
+ /* Offset: ‭0xFC4‬ (R/ ) Reserved */
+ volatile uint32_t reserved_1[6];
+ /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+ volatile uint32_t iidr;
+ /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+ volatile uint32_t aidr;
+ /* Offset: 0xFD0 (R/ ) */
+ volatile uint32_t pid_1[4];
+ /* Offset: 0xFE0 (R/ ) */
+ volatile uint32_t pid_0[4];
+ /* Offset: 0xFF0 (R/ ) */
+ volatile uint32_t cid[4];
+};
+
+struct _mhu_v2_x_rec_ch_window_t {
+ /* Offset: 0x00 (R/ ) Channel Status */
+ volatile uint32_t ch_st;
+ /* Offset: 0x04 (R/ ) Channel Status Masked */
+ volatile uint32_t ch_st_msk;
+ /* Offset: 0x08 ( /W) Channel Clear */
+ volatile uint32_t ch_clr;
+ /* Offset: 0x0C (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0x10 (R/ ) Channel Mask Status */
+ volatile uint32_t ch_msk_st;
+ /* Offset: 0x14 ( /W) Channel Mask Set */
+ volatile uint32_t ch_msk_set;
+ /* Offset: 0x18 ( /W) Channel Mask Clear */
+ volatile uint32_t ch_msk_clr;
+ /* Offset: 0x1C (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+};
+
+struct _mhu_v2_x_recv_frame_t {
+ /* Offset: 0x000 ( / ) Receiver Channel Window 0 -123 */
+ struct _mhu_v2_x_rec_ch_window_t rec_ch_window[_MHU_V2_X_MAX_CHANNELS];
+ /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+ volatile uint32_t mhu_cfg;
+ /* Offset: 0xF84 (R/ ) Reserved */
+ volatile uint32_t reserved_0[3];
+ /* Offset: 0xF90 (R/ ) Interrupt Status (Reserved in 2.0) */
+ volatile uint32_t int_st;
+ /* Offset: 0xF94 (R/ ) Interrupt Clear (Reserved in 2.0) */
+ volatile uint32_t int_clr;
+ /* Offset: 0xF98 (R/W) Interrupt Enable (Reserved in 2.0) */
+ volatile uint32_t int_en;
+ /* Offset: 0xF9C (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+ /* Offset: 0xFA0 (R/ ) Channel Combined Interrupt Stat (Reserved in 2.0) */
+ volatile uint32_t ch_comb_int_st[_MHU_V2_1_MAX_CHCOMB_INT];
+ /* Offset: 0xFB0 (R/ ) Reserved */
+ volatile uint32_t reserved_2[6];
+ /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+ volatile uint32_t iidr;
+ /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+ volatile uint32_t aidr;
+ /* Offset: 0xFD0 (R/ ) */
+ volatile uint32_t pid_1[4];
+ /* Offset: 0xFE0 (R/ ) */
+ volatile uint32_t pid_0[4];
+ /* Offset: 0xFF0 (R/ ) */
+ volatile uint32_t cid[4];
+};
+
+union _mhu_v2_x_frame_t {
+ struct _mhu_v2_x_send_frame_t send_frame;
+ struct _mhu_v2_x_recv_frame_t recv_frame;
+};
+
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+ enum mhu_v2_x_supported_revisions rev)
+{
+ uint32_t AIDR = 0;
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if (dev->is_initialized) {
+ return MHU_V_2_X_ERR_ALREADY_INIT;
+ }
+
+ if (rev == MHU_REV_READ_FROM_HW) {
+ /* Read revision from HW */
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ AIDR = p_mhu->recv_frame.aidr;
+ } else {
+ AIDR = p_mhu->send_frame.aidr;
+ }
+
+ /* Get bits 7:4 to read major revision */
+ if ( ((AIDR >> 4) & 0b1111) != MHU_MAJOR_REV_V2) {
+ /* Unsupported MHU version */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ } /* No need to save major version, driver only supports MHUv2 */
+
+ /* Get bits 3:0 to read minor revision */
+ dev->subversion = AIDR & 0b1111;
+
+ if (dev->subversion != MHU_MINOR_REV_2_0 &&
+ dev->subversion != MHU_MINOR_REV_2_1) {
+ /* Unsupported subversion */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ } else {
+ /* Revisions were provided by caller */
+ if (rev == MHU_REV_2_0) {
+ dev->subversion = MHU_MINOR_REV_2_0;
+ } else if (rev == MHU_REV_2_1) {
+ dev->subversion = MHU_MINOR_REV_2_1;
+ } else {
+ /* Unsupported subversion */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }/* No need to save major version, driver only supports MHUv2 */
+ }
+
+ dev->is_initialized = true;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+uint32_t mhu_v2_x_get_num_channel_implemented(const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ return (SEND_FRAME(p_mhu))->mhu_cfg;
+ } else {
+ return (RECV_FRAME(p_mhu))->mhu_cfg;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t val)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_set = val;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_clr = UINT32_MAX;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ *value = (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_st;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_set = mask;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_clr = mask;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_enable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_1) {
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_en = ENABLE;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_disable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_1) {
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_en = DISABLE;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_1) {
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_clr = CLEAR_INTR;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+ const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = ENABLE;
+
+ while ( !((SEND_FRAME(p_mhu))->access_ready) ) {
+ /* Wait in a loop for access ready signal to be high */
+ ;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = DISABLE;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_get_access_request(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *val)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ *val = (SEND_FRAME(p_mhu))->access_request;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_set_access_request(
+ const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = ENABLE;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_reset_access_request(
+ const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = DISABLE;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_get_access_ready(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *val)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ *val = (SEND_FRAME(p_mhu))->access_ready;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+uint32_t mhu_v2_x_get_interrupt_status(const struct mhu_v2_x_dev_t *dev)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ return (SEND_FRAME(p_mhu))->int_st;
+ } else {
+ return (RECV_FRAME(p_mhu))->int_st;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_enable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_0) {
+ if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+ /* Combined channel IRQ is not present in v2.0 */
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ /* Only sender frame has these registers */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->int_en |= mask;
+ } else {
+ (RECV_FRAME(p_mhu))->int_en |= mask;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_disable(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_0) {
+ if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+ /* Combined channel IRQ is not present in v2.0 */
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ /* Only sender frame has these registers */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->int_en &= ~mask;
+ } else {
+ (RECV_FRAME(p_mhu))->int_en &= ~mask;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion == MHU_MINOR_REV_2_0) {
+ if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+ /* Combined channel IRQ is not present in v2.0 */
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ /* Only sender frame has these registers */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ }
+
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->int_clr = mask;
+ } else {
+ (RECV_FRAME(p_mhu))->int_clr = mask;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_1_get_ch_interrupt_num(
+ const struct mhu_v2_x_dev_t *dev, uint32_t *channel)
+{
+ uint32_t i, j, status;
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->subversion != MHU_MINOR_REV_2_1) {
+ /* Feature is only supported in MHU v2.1 */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ for(i = 0; i < _MHU_V2_1_MAX_CHCOMB_INT; i++) {
+ if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+ status = (SEND_FRAME(p_mhu))->ch_comb_int_st[i];
+ } else {
+ status = (RECV_FRAME(p_mhu))->ch_comb_int_st[i];
+ }
+
+ for(j = 0; j < CH_PER_CH_COMB; j++) {
+ if ((status >> (CH_PER_CH_COMB - j - 1)) & (ENABLE)) {
+ *channel = (CH_PER_CH_COMB - j -1) + (i * CH_PER_CH_COMB);
+ return MHU_V_2_X_ERR_NONE;
+ }
+ }
+ }
+
+ return MHU_V_2_X_ERR_GENERAL;
+}
diff --git a/platform/drivers/arm/tztrng/driver.cmake b/platform/drivers/arm/tztrng/driver.cmake
index 6a7f93625..801d56eba 100644
--- a/platform/drivers/arm/tztrng/driver.cmake
+++ b/platform/drivers/arm/tztrng/driver.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -16,7 +16,7 @@ FetchContent_Declare(
arm-tztrng
GIT_REPOSITORY ${ARM_TZTRNG_URL}
GIT_TAG ${ARM_TZTRNG_REFSPEC}
- GIT_SHALLOW TRUE
+ GIT_SHALLOW FALSE
)
# FetchContent_GetProperties exports arm-tztrng_SOURCE_DIR and arm-tztrng_BINARY_DIR variables
diff --git a/platform/drivers/arm/tztrng/tztrng_adapter.c b/platform/drivers/arm/tztrng/tztrng_adapter.c
index f52eeaa56..bcabfd0b9 100644
--- a/platform/drivers/arm/tztrng/tztrng_adapter.c
+++ b/platform/drivers/arm/tztrng/tztrng_adapter.c
@@ -1,10 +1,12 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <config/interface/config_store.h>
#include <platform/interface/trng.h>
#include <platform/interface/device_region.h>
+#include <psa/error.h>
#include <tztrng.h>
#include <tztrng_defs.h>
#include <stdlib.h>
@@ -44,10 +46,11 @@ static int trng_poll(void *context, unsigned char *output, size_t nbyte, size_t
return status;
}
-int platform_trng_create(struct platform_trng_driver *driver,
- const struct device_region *device_region)
+int platform_trng_create(struct platform_trng_driver *driver, int instance)
{
static const struct platform_trng_iface iface = { .poll = trng_poll };
+ struct device_region device_region;
+ struct tztrng_instance *new_instance = NULL;
/*
* Default to leaving the driver in a safe but inoperable state.
@@ -55,22 +58,24 @@ int platform_trng_create(struct platform_trng_driver *driver,
driver->iface = &iface;
driver->context = NULL;
- if (device_region) {
+ if (!config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, "trng",
+ instance, &device_region,
+ sizeof(device_region)))
+ return PSA_STATUS_HARDWARE_FAILURE;
- /*
- * A device region has been provided, possibly from an external configuation.
- * Check that it's a sensible size to defend against a bogus configuration.
- */
- struct tztrng_instance *new_instance = malloc(sizeof(struct tztrng_instance));
+ /*
+ * A device region has been provided, possibly from an external configuation.
+ * Check that it's a sensible size to defend against a bogus configuration.
+ */
+ new_instance = malloc(sizeof(struct tztrng_instance));
- if (new_instance) {
+ if (!new_instance)
+ return PSA_ERROR_INSUFFICIENT_MEMORY;
- new_instance->trng_device_region = *device_region;
- driver->context = new_instance;
- }
- }
+ new_instance->trng_device_region = device_region;
+ driver->context = new_instance;
- return 0;
+ return PSA_SUCCESS;
}
void platform_trng_destroy(struct platform_trng_driver *driver)
diff --git a/platform/drivers/edk2-platforms/Platform/ARM/Morello/Drivers/CadenceQspiDxe.cmake b/platform/drivers/edk2-platforms/Platform/ARM/Morello/Drivers/CadenceQspiDxe.cmake
new file mode 100644
index 000000000..122dc428c
--- /dev/null
+++ b/platform/drivers/edk2-platforms/Platform/ARM/Morello/Drivers/CadenceQspiDxe.cmake
@@ -0,0 +1,15 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(_DRIVER_DIR "${EDK2_PLATFORMS_PATH}/Platform/ARM/Morello/Drivers/CadenceQspiDxe")
+
+target_sources(${TGT} PRIVATE
+ "${_DRIVER_DIR}/CadenceQspiDxe.c"
+ "${_DRIVER_DIR}/NorFlash.c"
+ "${_DRIVER_DIR}/NorFlashFvb.c"
+)
+
diff --git a/platform/drivers/mock/mock_trng.c b/platform/drivers/mock/mock_trng.c
index 24b14c0b2..a9f79f822 100644
--- a/platform/drivers/mock/mock_trng.c
+++ b/platform/drivers/mock/mock_trng.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -24,13 +24,11 @@ static int mock_poll(void *context, unsigned char *output, size_t nbyte, size_t
return 0;
}
-int platform_trng_create(struct platform_trng_driver *driver,
- const struct device_region *device_region)
+int platform_trng_create(struct platform_trng_driver *driver, int instance)
{
static const struct platform_trng_iface iface = { .poll = mock_poll };
- (void)device_region;
-
+ (void)instance;
driver->context = NULL;
driver->iface = &iface;
diff --git a/platform/drivers/tf-a/drivers/cfi/v2m/v2m_flash.cmake b/platform/drivers/tf-a/drivers/cfi/v2m/v2m_flash.cmake
new file mode 100644
index 000000000..cd6857200
--- /dev/null
+++ b/platform/drivers/tf-a/drivers/cfi/v2m/v2m_flash.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(_DRIVER_DIR "${TFA_SOURCE_DIR}/drivers/cfi/v2m")
+
+target_sources(${TGT} PRIVATE
+ "${_DRIVER_DIR}/v2m_flash.c"
+)
+
diff --git a/platform/drivers/tf-a/lib/semihosting/driver.cmake b/platform/drivers/tf-a/lib/semihosting/driver.cmake
new file mode 100644
index 000000000..3a3362883
--- /dev/null
+++ b/platform/drivers/tf-a/lib/semihosting/driver.cmake
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+#-------------------------------------------------------------------------------
+# Depends on the tf-a external component
+#-------------------------------------------------------------------------------
+set(_SEMIHOSTING_LIB_DIR "${TFA_SOURCE_DIR}/lib/semihosting")
+
+target_sources(${TGT} PRIVATE
+ "${_SEMIHOSTING_LIB_DIR}/semihosting.c"
+ "${_SEMIHOSTING_LIB_DIR}/aarch64/semihosting_call.S"
+)
+
diff --git a/platform/interface/trng.h b/platform/interface/trng.h
index 9c24581c4..0f1daf5bb 100644
--- a/platform/interface/trng.h
+++ b/platform/interface/trng.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -51,12 +51,11 @@ struct platform_trng_driver
* \brief Factory method to construct a platform specific trng driver
*
* \param driver Pointer to driver structure to initialize on construction.
- * \param device_region Pointer a device region object or NULL if none.
+ * \param instance Deployment specific trng instance.
*
* \return 0 if successful.
*/
-int platform_trng_create(struct platform_trng_driver *driver,
- const struct device_region *device_region);
+int platform_trng_create(struct platform_trng_driver *driver, int instance);
/**
* \brief Destroy a driver constructed using the factory method
diff --git a/platform/providers/arm/corstone1000/platform.cmake b/platform/providers/arm/corstone1000/platform.cmake
new file mode 100644
index 000000000..a3c4209b1
--- /dev/null
+++ b/platform/providers/arm/corstone1000/platform.cmake
@@ -0,0 +1,15 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform definition for the 'fvp_base_revc-2xaem8a' virtual platform.
+#-------------------------------------------------------------------------------
+
+# include MHU driver
+include(${TS_ROOT}/platform/drivers/arm/mhu_driver/component.cmake)
+
+target_compile_definitions(${TGT} PRIVATE
+ SMM_VARIABLE_INDEX_STORAGE_UID=0x787
+ SMM_GATEWAY_MAX_UEFI_VARIABLES=100
+)
diff --git a/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake b/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
index ff7c0492b..694fa8b82 100644
--- a/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
+++ b/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -13,6 +13,8 @@ get_property(_platform_driver_dependencies TARGET ${TGT}
PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
)
+set(CFG_SFS_FLASH_AREA_SIZE "32*1024" CACHE STRING "Size of SFS ram store")
+
#-------------------------------------------------------------------------------
# Map platform dependencies to suitable drivers for this platform
#
@@ -20,3 +22,11 @@ get_property(_platform_driver_dependencies TARGET ${TGT}
if ("trng" IN_LIST _platform_driver_dependencies)
include(${TS_ROOT}/platform/drivers/arm/juno_trng/driver.cmake)
endif()
+
+if ("secure-nor-flash" IN_LIST _platform_driver_dependencies)
+ include(${TS_ROOT}/platform/drivers/tf-a/drivers/cfi/v2m/v2m_flash.cmake)
+endif()
+
+if ("semihosting" IN_LIST _platform_driver_dependencies)
+ include(${TS_ROOT}/platform/drivers/tf-a/lib/semihosting/driver.cmake)
+endif() \ No newline at end of file
diff --git a/platform/providers/arm/n1sdp/platform.cmake b/platform/providers/arm/n1sdp/platform.cmake
new file mode 100644
index 000000000..dfbda5632
--- /dev/null
+++ b/platform/providers/arm/n1sdp/platform.cmake
@@ -0,0 +1,16 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform definition for the N1SDP development board
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+#-------------------------------------------------------------------------------
+# Map platform dependencies to suitable drivers for this platform
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/platform/drivers/edk2-platforms/Platform/ARM/Morello/Drivers/CadenceQspiDxe.cmake)
diff --git a/protocols/common/efi/efi_certificate.h b/protocols/common/efi/efi_certificate.h
new file mode 100644
index 000000000..fee19b46e
--- /dev/null
+++ b/protocols/common/efi/efi_certificate.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef COMMON_EFI_CERTIFICATE_H
+#define COMMON_EFI_CERTIFICATE_H
+
+#include <stdint.h>
+#include "efi_types.h"
+
+/* Certificate types (wCertificateType) */
+#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
+#define WIN_CERT_TYPE_EFI_PKCS115 0x0EF0
+#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
+
+/* Current WIN_CERTIFICATE version */
+#define WIN_CERT_CURRENT_VERSION 0x0200
+
+/**
+ * The Authenticode WIN_CERTIFICATE structure
+ */
+typedef struct {
+
+ /* Length of certificate plus header in bytes */
+ uint32_t dwLength;
+
+ /* The revision of this structure */
+ uint16_t wRevision;
+
+ /* Certificate type */
+ uint16_t wCertificateType;
+
+ /* Certificate bytes follow this structure */
+
+} WIN_CERTIFICATE;
+
+/**
+ * Extends WIN_CERTIFICATE for a GUID defined certificate type
+ * (wCertificateType in WIN_CERTIFICATE set to WIN_CERT_TYPE_EFI_GUID).
+ */
+typedef struct {
+
+ WIN_CERTIFICATE Hdr;
+ EFI_GUID CertType;
+ uint8_t CertData[1];
+
+} WIN_CERTIFICATE_UEFI_GUID;
+
+
+#endif /* COMMON_EFI_CERTIFICATE_H */
diff --git a/protocols/common/efi/efi_global_variable.h b/protocols/common/efi/efi_global_variable.h
new file mode 100644
index 000000000..d37a761cb
--- /dev/null
+++ b/protocols/common/efi/efi_global_variable.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __GLOBAL_VARIABLE_H__
+#define __GLOBAL_VARIABLE_H__
+
+#define EFI_GLOBAL_VARIABLE \
+{ \
+ 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } \
+}
+
+//
+// Follow UEFI 2.4 spec:
+// To prevent name collisions with possible future globally defined variables,
+// other internal firmware data variables that are not defined here must be
+// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or
+// any other GUID defined by the UEFI Specification. Implementations must
+// only permit the creation of variables with a UEFI Specification-defined
+// VendorGuid when these variables are documented in the UEFI Specification.
+//
+// Note: except the globally defined variables defined below, the spec also defines
+// u"Boot####" - A boot load option.
+// u"Driver####" - A driver load option.
+// u"SysPrep####" - A System Prep application load option.
+// u"Key####" - Describes hot key relationship with a Boot#### load option.
+// The attribute for them is NV+BS+RT, #### is a printed hex value, and no 0x or h
+// is included in the hex value. They can not be expressed as a #define like other globally
+// defined variables, it is because we can not list the Boot0000, Boot0001, etc one by one.
+//
+
+///
+/// The language codes that the firmware supports. This value is deprecated.
+/// Its attribute is BS+RT.
+///
+#define EFI_LANG_CODES_VARIABLE_NAME u"LangCodes"
+///
+/// The language code that the system is configured for. This value is deprecated.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_LANG_VARIABLE_NAME u"Lang"
+///
+/// The firmware's boot managers timeout, in seconds, before initiating the default boot selection.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_TIME_OUT_VARIABLE_NAME u"Timeout"
+///
+/// The language codes that the firmware supports.
+/// Its attribute is BS+RT.
+///
+#define EFI_PLATFORM_LANG_CODES_VARIABLE_NAME u"PlatformLangCodes"
+///
+/// The language code that the system is configured for.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_PLATFORM_LANG_VARIABLE_NAME u"PlatformLang"
+///
+/// The device path of the default input/output/error output console.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_CON_IN_VARIABLE_NAME u"ConIn"
+#define EFI_CON_OUT_VARIABLE_NAME u"ConOut"
+#define EFI_ERR_OUT_VARIABLE_NAME u"ErrOut"
+///
+/// The device path of all possible input/output/error output devices.
+/// Its attribute is BS+RT.
+///
+#define EFI_CON_IN_DEV_VARIABLE_NAME u"ConInDev"
+#define EFI_CON_OUT_DEV_VARIABLE_NAME u"ConOutDev"
+#define EFI_ERR_OUT_DEV_VARIABLE_NAME u"ErrOutDev"
+///
+/// The ordered boot option load list.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_BOOT_ORDER_VARIABLE_NAME u"BootOrder"
+///
+/// The boot option for the next boot only.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_BOOT_NEXT_VARIABLE_NAME u"BootNext"
+///
+/// The boot option that was selected for the current boot.
+/// Its attribute is BS+RT.
+///
+#define EFI_BOOT_CURRENT_VARIABLE_NAME u"BootCurrent"
+///
+/// The types of boot options supported by the boot manager. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME u"BootOptionSupport"
+///
+/// The ordered driver load option list.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_DRIVER_ORDER_VARIABLE_NAME u"DriverOrder"
+///
+/// The ordered System Prep Application load option list.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_SYS_PREP_ORDER_VARIABLE_NAME u"SysPrepOrder"
+///
+/// Identifies the level of hardware error record persistence
+/// support implemented by the platform. This variable is
+/// only modified by firmware and is read-only to the OS.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME u"HwErrRecSupport"
+///
+/// Whether the system is operating in setup mode (1) or not (0).
+/// All other values are reserved. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_SETUP_MODE_NAME u"SetupMode"
+///
+/// The Key Exchange Key Signature Database.
+/// Its attribute is NV+BS+RT+AT.
+///
+#define EFI_KEY_EXCHANGE_KEY_NAME u"KEK"
+///
+/// The public Platform Key.
+/// Its attribute is NV+BS+RT+AT.
+///
+#define EFI_PLATFORM_KEY_NAME u"PK"
+///
+/// Array of GUIDs representing the type of signatures supported
+/// by the platform firmware. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_SIGNATURE_SUPPORT_NAME u"SignatureSupport"
+///
+/// Whether the platform firmware is operating in Secure boot mode (1) or not (0).
+/// All other values are reserved. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_SECURE_BOOT_MODE_NAME u"SecureBoot"
+///
+/// The OEM's default Key Exchange Key Signature Database. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_KEK_DEFAULT_VARIABLE_NAME u"KEKDefault"
+///
+/// The OEM's default public Platform Key. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_PK_DEFAULT_VARIABLE_NAME u"PKDefault"
+///
+/// The OEM's default secure boot signature store. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_DB_DEFAULT_VARIABLE_NAME u"dbDefault"
+///
+/// The OEM's default secure boot blacklist signature store. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_DBX_DEFAULT_VARIABLE_NAME u"dbxDefault"
+///
+/// The OEM's default secure boot timestamp signature store. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_DBT_DEFAULT_VARIABLE_NAME u"dbtDefault"
+///
+/// Allows the firmware to indicate supported features and actions to the OS.
+/// Its attribute is BS+RT.
+///
+#define EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME u"OsIndicationsSupported"
+///
+/// Allows the OS to request the firmware to enable certain features and to take certain actions.
+/// Its attribute is NV+BS+RT.
+///
+#define EFI_OS_INDICATIONS_VARIABLE_NAME u"OsIndications"
+///
+/// Whether the system is configured to use only vendor provided
+/// keys or not. Should be treated as read-only.
+/// Its attribute is BS+RT.
+///
+#define EFI_VENDOR_KEYS_VARIABLE_NAME u"VendorKeys"
+
+#endif /* __GLOBAL_VARIABLE_H__ */
diff --git a/protocols/common/efi/efi_image_authentication.h b/protocols/common/efi/efi_image_authentication.h
new file mode 100644
index 000000000..5f28ad9d2
--- /dev/null
+++ b/protocols/common/efi/efi_image_authentication.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __IMAGE_AUTHTICATION_H__
+#define __IMAGE_AUTHTICATION_H__
+
+#include <stdint.h>
+#include <protocols/common/efi/efi_types.h>
+
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
+ { \
+ 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f } \
+ }
+
+///
+/// Variable name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
+/// for the authorized signature database.
+///
+#define EFI_IMAGE_SECURITY_DATABASE u"db"
+///
+/// Variable name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
+/// for the forbidden signature database.
+///
+#define EFI_IMAGE_SECURITY_DATABASE1 u"dbx"
+///
+/// Variable name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
+/// for the timestamp signature database.
+///
+#define EFI_IMAGE_SECURITY_DATABASE2 u"dbt"
+///
+/// Variable name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
+/// for the recovery signature database.
+///
+#define EFI_IMAGE_SECURITY_DATABASE3 u"dbr"
+
+// ***********************************************************************
+// Signature Database
+// ***********************************************************************
+///
+/// The format of a signature database.
+///
+#pragma pack(push, 1)
+
+typedef struct {
+ ///
+ /// An identifier which identifies the agent which added the signature to the list.
+ ///
+ EFI_GUID SignatureOwner;
+ ///
+ /// The format of the signature is defined by the SignatureType.
+ ///
+ uint8_t SignatureData[1];
+} EFI_SIGNATURE_DATA;
+
+typedef struct {
+ ///
+ /// Type of the signature. GUID signature types are defined in below.
+ ///
+ EFI_GUID SignatureType;
+ ///
+ /// Total size of the signature list, including this header.
+ ///
+ uint32_t SignatureListSize;
+ ///
+ /// Size of the signature header which precedes the array of signatures.
+ ///
+ uint32_t SignatureHeaderSize;
+ ///
+ /// Size of each signature.
+ ///
+ uint32_t SignatureSize;
+ ///
+ /// Header before the array of signatures. The format of this header is specified
+ /// by the SignatureType.
+ /// uint8_t SignatureHeader[SignatureHeaderSize];
+ ///
+ /// An array of signatures. Each signature is SignatureSize bytes in length.
+ /// EFI_SIGNATURE_DATA Signatures[][SignatureSize];
+ ///
+} EFI_SIGNATURE_LIST;
+
+/* IMPORTED SECTION BEGIN */
+/* This section was imported from MdePkg/Include/Protocol/Hash.h inside EDK2 repository */
+typedef uint8_t EFI_MD5_HASH[16];
+typedef uint8_t EFI_SHA1_HASH[20];
+typedef uint8_t EFI_SHA224_HASH[28];
+typedef uint8_t EFI_SHA256_HASH[32];
+typedef uint8_t EFI_SHA384_HASH[48];
+typedef uint8_t EFI_SHA512_HASH[64];
+/* IMPORTED SECTION END */
+
+typedef struct {
+ ///
+ /// The SHA256 hash of an X.509 certificate's To-Be-Signed contents.
+ ///
+ EFI_SHA256_HASH ToBeSignedHash;
+ ///
+ /// The time that the certificate shall be considered to be revoked.
+ ///
+ EFI_TIME TimeOfRevocation;
+} EFI_CERT_X509_SHA256;
+
+typedef struct {
+ ///
+ /// The SHA384 hash of an X.509 certificate's To-Be-Signed contents.
+ ///
+ EFI_SHA384_HASH ToBeSignedHash;
+ ///
+ /// The time that the certificate shall be considered to be revoked.
+ ///
+ EFI_TIME TimeOfRevocation;
+} EFI_CERT_X509_SHA384;
+
+typedef struct {
+ ///
+ /// The SHA512 hash of an X.509 certificate's To-Be-Signed contents.
+ ///
+ EFI_SHA512_HASH ToBeSignedHash;
+ ///
+ /// The time that the certificate shall be considered to be revoked.
+ ///
+ EFI_TIME TimeOfRevocation;
+} EFI_CERT_X509_SHA512;
+
+#pragma pack(pop)
+
+///
+/// This identifies a signature containing a SHA-256 hash. The SignatureHeader size shall
+/// always be 0. The SignatureSize shall always be 16 (size of SignatureOwner component) +
+/// 32 bytes.
+///
+#define EFI_CERT_SHA256_GUID \
+ { \
+ 0xc1c41626, 0x504c, 0x4092, {0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28} \
+ }
+
+///
+/// This identifies a signature containing an RSA-2048 key. The key (only the modulus
+/// since the public key exponent is known to be 0x10001) shall be stored in big-endian
+/// order.
+/// The SignatureHeader size shall always be 0. The SignatureSize shall always be 16 (size
+/// of SignatureOwner component) + 256 bytes.
+///
+#define EFI_CERT_RSA2048_GUID \
+ { \
+ 0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} \
+ }
+
+///
+/// This identifies a signature containing a RSA-2048 signature of a SHA-256 hash. The
+/// SignatureHeader size shall always be 0. The SignatureSize shall always be 16 (size of
+/// SignatureOwner component) + 256 bytes.
+///
+#define EFI_CERT_RSA2048_SHA256_GUID \
+ { \
+ 0xe2b36190, 0x879b, 0x4a3d, {0xad, 0x8d, 0xf2, 0xe7, 0xbb, 0xa3, 0x27, 0x84} \
+ }
+
+///
+/// This identifies a signature containing a SHA-1 hash. The SignatureSize shall always
+/// be 16 (size of SignatureOwner component) + 20 bytes.
+///
+#define EFI_CERT_SHA1_GUID \
+ { \
+ 0x826ca512, 0xcf10, 0x4ac9, {0xb1, 0x87, 0xbe, 0x1, 0x49, 0x66, 0x31, 0xbd} \
+ }
+
+///
+/// TThis identifies a signature containing a RSA-2048 signature of a SHA-1 hash. The
+/// SignatureHeader size shall always be 0. The SignatureSize shall always be 16 (size of
+/// SignatureOwner component) + 256 bytes.
+///
+#define EFI_CERT_RSA2048_SHA1_GUID \
+ { \
+ 0x67f8444f, 0x8743, 0x48f1, {0xa3, 0x28, 0x1e, 0xaa, 0xb8, 0x73, 0x60, 0x80} \
+ }
+
+///
+/// This identifies a signature based on an X.509 certificate. If the signature is an X.509
+/// certificate then verification of the signature of an image should validate the public
+/// key certificate in the image using certificate path verification, up to this X.509
+/// certificate as a trusted root. The SignatureHeader size shall always be 0. The
+/// SignatureSize may vary but shall always be 16 (size of the SignatureOwner component) +
+/// the size of the certificate itself.
+/// Note: This means that each certificate will normally be in a separate EFI_SIGNATURE_LIST.
+///
+#define EFI_CERT_X509_GUID \
+ { \
+ 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} \
+ }
+
+///
+/// This identifies a signature containing a SHA-224 hash. The SignatureHeader size shall
+/// always be 0. The SignatureSize shall always be 16 (size of SignatureOwner component) +
+/// 28 bytes.
+///
+#define EFI_CERT_SHA224_GUID \
+ { \
+ 0xb6e5233, 0xa65c, 0x44c9, {0x94, 0x7, 0xd9, 0xab, 0x83, 0xbf, 0xc8, 0xbd} \
+ }
+
+///
+/// This identifies a signature containing a SHA-384 hash. The SignatureHeader size shall
+/// always be 0. The SignatureSize shall always be 16 (size of SignatureOwner component) +
+/// 48 bytes.
+///
+#define EFI_CERT_SHA384_GUID \
+ { \
+ 0xff3e5307, 0x9fd0, 0x48c9, {0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x1} \
+ }
+
+///
+/// This identifies a signature containing a SHA-512 hash. The SignatureHeader size shall
+/// always be 0. The SignatureSize shall always be 16 (size of SignatureOwner component) +
+/// 64 bytes.
+///
+#define EFI_CERT_SHA512_GUID \
+ { \
+ 0x93e0fae, 0xa6c4, 0x4f50, {0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a} \
+ }
+
+///
+/// This identifies a signature containing the SHA256 hash of an X.509 certificate's
+/// To-Be-Signed contents, and a time of revocation. The SignatureHeader size shall
+/// always be 0. The SignatureSize shall always be 16 (size of the SignatureOwner component)
+/// + 48 bytes for an EFI_CERT_X509_SHA256 structure. If the TimeOfRevocation is non-zero,
+/// the certificate should be considered to be revoked from that time and onwards, and
+/// otherwise the certificate shall be considered to always be revoked.
+///
+#define EFI_CERT_X509_SHA256_GUID \
+ { \
+ 0x3bd2a492, 0x96c0, 0x4079, {0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed } \
+ }
+
+///
+/// This identifies a signature containing the SHA384 hash of an X.509 certificate's
+/// To-Be-Signed contents, and a time of revocation. The SignatureHeader size shall
+/// always be 0. The SignatureSize shall always be 16 (size of the SignatureOwner component)
+/// + 64 bytes for an EFI_CERT_X509_SHA384 structure. If the TimeOfRevocation is non-zero,
+/// the certificate should be considered to be revoked from that time and onwards, and
+/// otherwise the certificate shall be considered to always be revoked.
+///
+#define EFI_CERT_X509_SHA384_GUID \
+ { \
+ 0x7076876e, 0x80c2, 0x4ee6, {0xaa, 0xd2, 0x28, 0xb3, 0x49, 0xa6, 0x86, 0x5b } \
+ }
+
+///
+/// This identifies a signature containing the SHA512 hash of an X.509 certificate's
+/// To-Be-Signed contents, and a time of revocation. The SignatureHeader size shall
+/// always be 0. The SignatureSize shall always be 16 (size of the SignatureOwner component)
+/// + 80 bytes for an EFI_CERT_X509_SHA512 structure. If the TimeOfRevocation is non-zero,
+/// the certificate should be considered to be revoked from that time and onwards, and
+/// otherwise the certificate shall be considered to always be revoked.
+///
+#define EFI_CERT_X509_SHA512_GUID \
+ { \
+ 0x446dbf63, 0x2502, 0x4cda, {0xbc, 0xfa, 0x24, 0x65, 0xd2, 0xb0, 0xfe, 0x9d } \
+ }
+
+///
+/// This identifies a signature containing a DER-encoded PKCS #7 version 1.5 [RFC2315]
+/// SignedData value.
+///
+#define EFI_CERT_TYPE_PKCS7_GUID \
+ { \
+ 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \
+ }
+
+#endif /* __IMAGE_AUTHTICATION_H__ */
diff --git a/protocols/common/efi/efi_types.h b/protocols/common/efi/efi_types.h
index 4998c5311..f37848bfd 100644
--- a/protocols/common/efi/efi_types.h
+++ b/protocols/common/efi/efi_types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,23 @@ typedef struct {
} EFI_GUID;
/**
+ * Common time representation
+ */
+typedef struct {
+ uint16_t Year;
+ uint8_t Month;
+ uint8_t Day;
+ uint8_t Hour;
+ uint8_t Minute;
+ uint8_t Second;
+ uint8_t Pad1;
+ uint32_t Nanosecond;
+ uint16_t TimeZone;
+ uint8_t Daylight;
+ uint8_t Pad2;
+} EFI_TIME;
+
+/**
* Header structure of messages in the MM communication buffer.
*/
typedef struct {
diff --git a/protocols/common/osf/uuid.h b/protocols/common/osf/uuid.h
new file mode 100644
index 000000000..be0e9ea8c
--- /dev/null
+++ b/protocols/common/osf/uuid.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Common Open Software Foundation (OSF) standards-based definitions
+ */
+
+#ifndef COMMON_OSF_UUID_H
+#define COMMON_OSF_UUID_H
+
+/**
+ * Octet length for standard binary encoded UUID in Big Endian byte order (see RFC4122)
+ */
+#define OSF_UUID_OCTET_LEN (16)
+
+/**
+ * Character length of a canonical form UUID string
+ * e.g. 123e4567-e89b-12d3-a456-426614174000
+ */
+#define OSF_UUID_CANONICAL_FORM_LEN (36)
+
+#endif /* COMMON_OSF_UUID_H */
diff --git a/protocols/service/block_storage/packed-c/messages.h b/protocols/service/block_storage/packed-c/messages.h
new file mode 100644
index 000000000..215588904
--- /dev/null
+++ b/protocols/service/block_storage/packed-c/messages.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_BLOCK_STORAGE_PACKEDC_MESSAGES_H
+#define TS_BLOCK_STORAGE_PACKEDC_MESSAGES_H
+
+#include <stdint.h>
+
+/**
+ * Protocol definitions for block storage operations
+ * using the packed-c serialization.
+ */
+
+/****************************************
+ * Common defines
+ */
+#define TS_BLOCK_STORAGE_GUID_OCTET_LEN (16)
+
+/****************************************
+ * \brief get_partition_info operation
+ *
+ * Get information about the storage partition identified by the specified
+ * unique partition GUID.
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_get_partition_info_in
+{
+ uint8_t partition_guid[TS_BLOCK_STORAGE_GUID_OCTET_LEN];
+};
+
+/* Mandatory fixed sized output parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_get_partition_info_out
+{
+ uint64_t num_blocks;
+ uint32_t block_size;
+ uint8_t partition_guid[TS_BLOCK_STORAGE_GUID_OCTET_LEN];
+ uint8_t parent_guid[TS_BLOCK_STORAGE_GUID_OCTET_LEN];
+};
+
+/****************************************
+ * \brief open operation
+ *
+ * Open the storage partition identified by the specified unique partition
+ * GUID. A handle is returned that should be used as a qualifier for subsequent
+ * partition-oriented operations.
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_open_in
+{
+ uint8_t partition_guid[TS_BLOCK_STORAGE_GUID_OCTET_LEN];
+};
+
+/* Mandatory fixed sized output parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_open_out
+{
+ uint64_t handle;
+};
+
+/****************************************
+ * \brief close operation
+ *
+ * Close a previously opened storage partition. Used when access to the storage
+ * partition is no longer required.
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_close_in
+{
+ uint64_t handle;
+};
+
+/****************************************
+ * \brief read operation
+ *
+ * Read data from the block identified by the specified LBA.
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_read_in
+{
+ uint64_t handle;
+ uint64_t lba;
+ uint32_t offset;
+ uint32_t len;
+};
+
+/* Read data returned in response */
+
+/****************************************
+ * \brief write operation
+ *
+ * Write data to the block identified by the specified LBA.
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_write_in
+{
+ uint64_t handle;
+ uint64_t lba;
+ uint32_t offset;
+};
+
+/* Write data follows fixed size input message */
+
+/* Mandatory fixed sized output parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_write_out
+{
+ uint64_t num_written;
+};
+
+/****************************************
+ * \brief erase operation
+ *
+ * Erase the set of blocks identified by the specified set of LBAs.
+ */
+
+/* Mandatory fixed sized input parameters */
+struct __attribute__ ((__packed__)) ts_block_storage_erase_in
+{
+ uint64_t handle;
+ uint64_t begin_lba;
+ uint32_t num_blocks;
+};
+
+#endif /* TS_BLOCK_STORAGE_PACKEDC_MESSAGES_H */
diff --git a/protocols/service/block_storage/packed-c/opcodes.h b/protocols/service/block_storage/packed-c/opcodes.h
new file mode 100644
index 000000000..2836b1ce2
--- /dev/null
+++ b/protocols/service/block_storage/packed-c/opcodes.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_BLOCK_STORAGE_OPCODES_H
+#define TS_BLOCK_STORAGE_OPCODES_H
+
+/**
+ * C/C++ definition of block storage service opcodes.
+ */
+
+#define TS_BLOCK_STORAGE_OPCODE_BASE (0x0100)
+#define TS_BLOCK_STORAGE_OPCODE_GET_PARTITION_INFO (TS_BLOCK_STORAGE_OPCODE_BASE + 1)
+#define TS_BLOCK_STORAGE_OPCODE_OPEN (TS_BLOCK_STORAGE_OPCODE_BASE + 2)
+#define TS_BLOCK_STORAGE_OPCODE_CLOSE (TS_BLOCK_STORAGE_OPCODE_BASE + 3)
+#define TS_BLOCK_STORAGE_OPCODE_READ (TS_BLOCK_STORAGE_OPCODE_BASE + 4)
+#define TS_BLOCK_STORAGE_OPCODE_WRITE (TS_BLOCK_STORAGE_OPCODE_BASE + 5)
+#define TS_BLOCK_STORAGE_OPCODE_ERASE (TS_BLOCK_STORAGE_OPCODE_BASE + 6)
+
+#endif /* TS_BLOCK_STORAGE_OPCODES_H */
diff --git a/protocols/service/crypto/packed-c/opcodes.h b/protocols/service/crypto/packed-c/opcodes.h
index a07bd57eb..35b81599b 100644
--- a/protocols/service/crypto/packed-c/opcodes.h
+++ b/protocols/service/crypto/packed-c/opcodes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,9 @@
#define TS_CRYPTO_OPCODE_COPY_KEY (TS_CRYPTO_OPCODE_BASE + 13)
#define TS_CRYPTO_OPCODE_PURGE_KEY (TS_CRYPTO_OPCODE_BASE + 14)
#define TS_CRYPTO_OPCODE_GET_KEY_ATTRIBUTES (TS_CRYPTO_OPCODE_BASE + 15)
+#define TS_CRYPTO_OPCODE_SIGN_MESSAGE (TS_CRYPTO_OPCODE_BASE + 16)
+#define TS_CRYPTO_OPCODE_VERIFY_MESSAGE (TS_CRYPTO_OPCODE_BASE + 17)
+#define TS_CRYPTO_OPCODE_VERIFY_PKCS7_SIGNATURE (TS_CRYPTO_OPCODE_BASE + 18)
/* Hash operations */
#define TS_CRYPTO_OPCODE_HASH_BASE (0x0200)
diff --git a/protocols/service/crypto/packed-c/verify_pkcs7_signature.h b/protocols/service/crypto/packed-c/verify_pkcs7_signature.h
new file mode 100644
index 000000000..5b32d3fc8
--- /dev/null
+++ b/protocols/service/crypto/packed-c/verify_pkcs7_signature.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_H
+#define TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_H
+
+#include <stdint.h>
+
+/* Variable length input parameter tags */
+enum {
+ TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_SIGNATURE = 1,
+ TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_HASH = 2,
+ TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_PUBLIC_KEY_CERT = 3
+};
+
+#endif /* TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_H */
diff --git a/protocols/service/crypto/protobuf/opcodes.proto b/protocols/service/crypto/protobuf/opcodes.proto
index 094d3a020..ef64d044b 100644
--- a/protocols/service/crypto/protobuf/opcodes.proto
+++ b/protocols/service/crypto/protobuf/opcodes.proto
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
syntax = "proto3";
@@ -18,4 +18,6 @@ enum Opcode {
ASYMMETRIC_DECRYPT = 0x010a;
ASYMMETRIC_ENCRYPT = 0x010b;
GENERATE_RANDOM = 0x010c;
+ SIGN_MESSAGE = 0x0110;
+ VERIFY_MESSAGE = 0x0111;
}
diff --git a/protocols/service/fwu/packed-c/fwu_proto.h b/protocols/service/fwu/packed-c/fwu_proto.h
new file mode 100644
index 000000000..6cd691acc
--- /dev/null
+++ b/protocols/service/fwu/packed-c/fwu_proto.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_PROTO_H
+#define FWU_PROTO_H
+
+#include <stdint.h>
+
+#include "opcodes.h"
+#include "protocols/common/osf/uuid.h"
+#include "status.h"
+
+/**
+ * The major version number of the FWU-A access protocol. It will be incremented
+ * on significant updates that may include breaking changes.
+ */
+#define FWU_PROTOCOL_VERSION_MAJOR 2
+
+/**
+ * The minor version number It will be incremented in
+ * small updates that are unlikely to include breaking changes.
+ */
+#define FWU_PROTOCOL_VERSION_MINOR 0
+
+/**
+ * Protocol GUIDs defined in FWU-A specification
+ */
+#define FWU_UPDATE_AGENT_CANONICAL_UUID "6823a838-1b06-470e-9774-0cce8bfb53fd"
+#define FWU_DIRECTORY_CANONICAL_UUID "deee58d9-5147-4ad3-a290-77666e2341a5"
+#define FWU_METADATA_CANONICAL_UUID "8a7a84a0-8387-40f6-ab41-a8b9a5a60d23"
+
+/**
+ * Image directory
+ */
+#define FWU_READ_PERM (1u << 1)
+#define FWU_WRITE_PERM (1u << 0)
+
+struct __attribute__((__packed__)) ts_fwu_image_info_entry {
+ uint8_t img_type_uuid[OSF_UUID_OCTET_LEN];
+ uint32_t client_permissions;
+ uint32_t img_max_size;
+ uint32_t lowest_accepted_version;
+ uint32_t img_version;
+ uint32_t accepted;
+ uint32_t reserved;
+};
+
+struct __attribute__((__packed__)) ts_fwu_image_directory {
+ uint32_t directory_version;
+ uint32_t img_info_offset;
+ uint32_t num_images;
+ uint32_t correct_boot;
+ uint32_t img_info_size;
+ uint32_t reserved;
+ struct ts_fwu_image_info_entry img_info_entry[];
+};
+
+/**
+ * Message parameters
+ */
+
+struct __attribute__((__packed__)) ts_fwu_discover_out {
+ uint8_t version_major;
+ uint8_t version_minor;
+ uint16_t num_func;
+ uint8_t function_presence[];
+};
+
+struct __attribute__((__packed__)) ts_fwu_open_in {
+ uint8_t image_type_uuid[OSF_UUID_OCTET_LEN];
+};
+
+struct __attribute__((__packed__)) ts_fwu_open_out {
+ uint32_t handle;
+};
+
+struct __attribute__((__packed__)) ts_fwu_write_stream_in {
+ uint32_t handle;
+ uint32_t data_len;
+ uint8_t payload[];
+};
+
+struct __attribute__((__packed__)) ts_fwu_read_stream_in {
+ uint32_t handle;
+};
+
+struct __attribute__((__packed__)) ts_fwu_read_stream_out {
+ uint32_t read_bytes;
+ uint32_t total_bytes;
+ uint8_t payload[];
+};
+
+struct __attribute__((__packed__)) ts_fwu_commit_in {
+ uint32_t handle;
+ uint32_t acceptance_req;
+ uint32_t max_atomic_len;
+};
+
+struct __attribute__((__packed__)) ts_fwu_commit_out {
+ uint32_t progress;
+ uint32_t total_work;
+};
+
+struct __attribute__((__packed__)) ts_fwu_accept_image_in {
+ uint32_t reserved;
+ uint8_t image_type_uuid[OSF_UUID_OCTET_LEN];
+};
+
+#endif /* FWU_PROTO_H */
diff --git a/protocols/service/fwu/packed-c/metadata.h b/protocols/service/fwu/packed-c/metadata.h
new file mode 100644
index 000000000..7a3c4fb23
--- /dev/null
+++ b/protocols/service/fwu/packed-c/metadata.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * FWU metadata information as per the specification section 4.1:
+ * https://developer.arm.com/documentation/den0118/a/
+ *
+ */
+
+#ifndef FWU_PROTO_METADATA_H
+#define FWU_PROTO_METADATA_H
+
+/**
+ * The number of banks for different versions of firmware.
+ * With the default configuration, a dual bank A/B scheme is used.
+ */
+#ifndef FWU_METADATA_NUM_BANKS
+#define FWU_METADATA_NUM_BANKS (2)
+#endif
+
+#endif /* FWU_PROTO_METADATA_H */
diff --git a/protocols/service/fwu/packed-c/metadata_v1.h b/protocols/service/fwu/packed-c/metadata_v1.h
new file mode 100644
index 000000000..cb264dacc
--- /dev/null
+++ b/protocols/service/fwu/packed-c/metadata_v1.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * FWU metadata information as per the specification section 4.1:
+ * https://developer.arm.com/documentation/den0118/a/
+ *
+ */
+
+#ifndef FWU_PROTO_METADATA_V1_H
+#define FWU_PROTO_METADATA_V1_H
+
+#include <stdint.h>
+
+#include "metadata.h"
+#include "protocols/common/osf/uuid.h"
+
+/**
+ * FWU metadata version corresponding to these structure definitions.
+ */
+#define FWU_METADATA_VERSION (1)
+
+/**
+ * The number of image entries in the metadata structure.
+ */
+#ifndef FWU_METADATA_NUM_IMAGE_ENTRIES
+#define FWU_METADATA_NUM_IMAGE_ENTRIES (1)
+#endif
+
+/* Properties of image in a bank */
+struct __attribute__((__packed__)) fwu_image_properties {
+ /* UUID of the image in this bank */
+ uint8_t img_uuid[OSF_UUID_OCTET_LEN];
+
+ /* [0]: bit describing the image acceptance status –
+ * 1 means the image is accepted
+ * [31:1]: MBZ
+ */
+ uint32_t accepted;
+
+ /* reserved (MBZ) */
+ uint32_t reserved;
+};
+
+/* Image entry information */
+struct __attribute__((__packed__)) fwu_image_entry {
+ /* UUID identifying the image type */
+ uint8_t img_type_uuid[OSF_UUID_OCTET_LEN];
+
+ /* UUID of the storage volume where the image is located */
+ uint8_t location_uuid[OSF_UUID_OCTET_LEN];
+
+ /* Properties of images with img_type_uuid in the different FW banks */
+ struct fwu_image_properties img_props[FWU_METADATA_NUM_BANKS];
+};
+
+/*
+ * FWU metadata filled by the updater and consumed by TF-A for
+ * various purposes as below:
+ * 1. Get active FW bank.
+ * 2. Rollback to previous working FW bank.
+ * 3. Get properties of all images present in all banks.
+ */
+struct __attribute__((__packed__)) fwu_metadata {
+ /* Metadata CRC value */
+ uint32_t crc_32;
+
+ /* Metadata version */
+ uint32_t version;
+
+ /* Bank index with which device boots */
+ uint32_t active_index;
+
+ /* Previous bank index with which device booted successfully */
+ uint32_t previous_active_index;
+
+ /* Image entry information */
+ struct fwu_image_entry img_entry[FWU_METADATA_NUM_IMAGE_ENTRIES];
+};
+
+#endif /* FWU_PROTO_METADATA_V1_H */
diff --git a/protocols/service/fwu/packed-c/metadata_v2.h b/protocols/service/fwu/packed-c/metadata_v2.h
new file mode 100644
index 000000000..33efb3399
--- /dev/null
+++ b/protocols/service/fwu/packed-c/metadata_v2.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * FWU metadata information as per the specification section 4.1:
+ * https://developer.arm.com/documentation/den0118/a/
+ *
+ */
+
+#ifndef FWU_PROTO_METADATA_V2_H
+#define FWU_PROTO_METADATA_V2_H
+
+#include <stdint.h>
+
+#include "metadata.h"
+#include "protocols/common/osf/uuid.h"
+
+/* Bank state definitions */
+#define FWU_METADATA_V2_NUM_BANK_STATES (4)
+#define FWU_METADATA_V2_BANK_STATE_INVALID (0xff)
+#define FWU_METADATA_V2_BANK_STATE_VALID (0xfe)
+#define FWU_METADATA_V2_BANK_STATE_ACCEPTED (0xfc)
+
+/*
+ * Version 2 FWU metadata data structure (mandatory)
+ *
+ * The metadata structure is variable length. The actual length is determined
+ * from the metadata_size member.
+ */
+struct __attribute__((__packed__)) fwu_metadata {
+ /* Metadata CRC value */
+ uint32_t crc_32;
+
+ /* Metadata version */
+ uint32_t version;
+
+ /* The overall metadata size */
+ uint32_t metadata_size;
+
+ /* The size in bytes of the fixed size header */
+ uint16_t header_size;
+
+ /* Active bank index as directed by update agent [0..n] */
+ uint8_t active_index;
+
+ /* Previous active bank index [0..n] */
+ uint8_t previous_active_index;
+
+ /* Bank state bitmaps */
+ uint8_t bank_state[FWU_METADATA_V2_NUM_BANK_STATES];
+};
+
+/* Properties of image in a bank */
+struct __attribute__((__packed__)) fwu_img_bank_info {
+ /* UUID of the image in this bank */
+ uint8_t img_uuid[OSF_UUID_OCTET_LEN];
+
+ /* [0]: bit describing the image acceptance status –
+ * 1 means the image is accepted
+ * [31:1]: MBZ
+ */
+ uint32_t accepted;
+
+ /* reserved (MBZ) */
+ uint32_t reserved;
+};
+
+/* Image entry information */
+struct __attribute__((__packed__)) fwu_image_entry {
+ /* UUID identifying the image type */
+ uint8_t img_type_uuid[OSF_UUID_OCTET_LEN];
+
+ /* UUID of the storage volume where the image is located (e.g. a disk UUID) */
+ uint8_t location_uuid[OSF_UUID_OCTET_LEN];
+
+ /* Per-bank info related to the image */
+ struct fwu_img_bank_info img_bank_info[FWU_METADATA_NUM_BANKS];
+};
+
+/*
+ * Firmware store descriptor
+ *
+ * FWU metadata may optionally include a description of the firmware store
+ * to direct the bootloader during boot. If a bootloader uses an alternative
+ * method to determine where to boot from, the fw_store_desc structure is
+ * not required. The fw_store_desc is assumed to be present if metadata_size
+ * > header_size.
+ */
+struct __attribute__((__packed__)) fwu_fw_store_desc {
+ /* Number of banks */
+ uint8_t num_banks;
+
+ /* Number of images listed in the img_entry array */
+ uint16_t num_images;
+
+ /* The size of the img_entry data structure */
+ uint16_t img_entry_size;
+
+ /* The size of bytes of the bank_entry data structure */
+ uint16_t bank_entry_size;
+
+ /* Array of image_entry structures */
+ struct fwu_image_entry img_entry[];
+};
+
+#endif /* FWU_PROTO_METADATA_V2_H */
diff --git a/protocols/service/fwu/packed-c/opcodes.h b/protocols/service/fwu/packed-c/opcodes.h
new file mode 100644
index 000000000..1905a65fd
--- /dev/null
+++ b/protocols/service/fwu/packed-c/opcodes.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_PROTO_OPCODES_H
+#define FWU_PROTO_OPCODES_H
+
+/**
+ * Service-level opcodes
+ */
+#define TS_FWU_OPCODE_BASE (0x10)
+#define TS_FWU_OPCODE_BEGIN_STAGING (TS_FWU_OPCODE_BASE + 0)
+#define TS_FWU_OPCODE_END_STAGING (TS_FWU_OPCODE_BASE + 1)
+#define TS_FWU_OPCODE_CANCEL_STAGING (TS_FWU_OPCODE_BASE + 2)
+#define TS_FWU_OPCODE_OPEN (TS_FWU_OPCODE_BASE + 3)
+#define TS_FWU_OPCODE_WRITE_STREAM (TS_FWU_OPCODE_BASE + 4)
+#define TS_FWU_OPCODE_READ_STREAM (TS_FWU_OPCODE_BASE + 5)
+#define TS_FWU_OPCODE_COMMIT (TS_FWU_OPCODE_BASE + 6)
+#define TS_FWU_OPCODE_ACCEPT_IMAGE (TS_FWU_OPCODE_BASE + 7)
+#define TS_FWU_OPCODE_SELECT_PREVIOUS (TS_FWU_OPCODE_BASE + 8)
+
+#endif /* FWU_PROTO_OPCODES_H */
diff --git a/protocols/service/fwu/packed-c/status.h b/protocols/service/fwu/packed-c/status.h
new file mode 100644
index 000000000..6d3e90b8a
--- /dev/null
+++ b/protocols/service/fwu/packed-c/status.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_PROTO_STATUS_H
+#define FWU_PROTO_STATUS_H
+
+/**
+ * Service-level status codes
+ */
+#define FWU_STATUS_SUCCESS ((int32_t)0)
+#define FWU_STATUS_UNKNOWN ((int32_t)-1)
+#define FWU_STATUS_BUSY ((int32_t)-2)
+#define FWU_STATUS_OUT_OF_BOUNDS ((int32_t)-3)
+#define FWU_STATUS_AUTH_FAIL ((int32_t)-4)
+#define FWU_STATUS_NO_PERMISSION ((int32_t)-5)
+#define FWU_STATUS_DENIED ((int32_t)-6)
+#define FWU_STATUS_RESUME ((int32_t)-7)
+#define FWU_STATUS_NOT_AVAILABLE ((int32_t)-8)
+
+#endif /* FWU_PROTO_STATUS_H */
diff --git a/protocols/service/rpmb/packed-c/rpmb_proto.h b/protocols/service/rpmb/packed-c/rpmb_proto.h
new file mode 100644
index 000000000..d9e6f11da
--- /dev/null
+++ b/protocols/service/rpmb/packed-c/rpmb_proto.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_PROTO_H
+#define RPMB_PROTO_H
+
+#include "components/service/rpmb/backend/rpmb_backend.h"
+#include "compiler.h"
+#include <stdint.h>
+
+/* Operation GET_DEV_INFO request parameters */
+struct rpmb_request_get_dev_info {
+ uint32_t dev_id;
+} __packed;
+
+/* Operation GET_DEV_INFO response parameters */
+struct rpmb_response_get_dev_info {
+ struct rpmb_dev_info dev_info;
+} __packed;
+
+/* Operation DATA_REQUEST request parameters */
+struct rpmb_request_data_request {
+ uint32_t dev_id;
+ uint32_t request_frame_count;
+ uint32_t max_response_frame_count;
+ struct rpmb_data_frame request_frames[];
+} __packed;
+
+/* Operation DATA_REQUEST response parameters */
+struct rpmb_response_data_request {
+ uint32_t response_frame_count;
+ struct rpmb_data_frame response_frames[];
+} __packed;
+
+#define TS_RPMB_OPCODE_GET_DEV_INFO (0u)
+#define TS_RPMB_OPCODE_DATA_REQUEST (1u)
+
+#endif /* RPMB_PROTO_H */
diff --git a/protocols/service/smm_variable/parameters.h b/protocols/service/smm_variable/parameters.h
index 1f795a9b4..610882444 100644
--- a/protocols/service/smm_variable/parameters.h
+++ b/protocols/service/smm_variable/parameters.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,8 +7,13 @@
#ifndef TS_SMM_VARIABLE_PARAMETERS_H
#define TS_SMM_VARIABLE_PARAMETERS_H
+#include <stddef.h>
+
#include "protocols/common/efi/efi_status.h"
#include "protocols/common/efi/efi_types.h"
+#include "protocols/common/efi/efi_certificate.h"
+#include <protocols/common/efi/efi_global_variable.h>
+#include <protocols/common/efi/efi_image_authentication.h>
/**
* C/C++ definition of smm_variable service parameters
@@ -33,20 +38,24 @@ typedef struct {
/**
* Variable attributes
*/
-#define EFI_VARIABLE_NON_VOLATILE (0x00000001)
-#define EFI_VARIABLE_BOOTSERVICE_ACCESS (0x00000002)
-#define EFI_VARIABLE_RUNTIME_ACCESS (0x00000004)
-#define EFI_VARIABLE_HARDWARE_ERROR_RECORD (0x00000008)
-#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS (0x00000010)
+#define EFI_VARIABLE_NON_VOLATILE (0x00000001)
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS (0x00000002)
+#define EFI_VARIABLE_RUNTIME_ACCESS (0x00000004)
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD (0x00000008)
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS (0x00000010)
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS (0x00000020)
-#define EFI_VARIABLE_APPEND_WRITE (0x00000040)
+#define EFI_VARIABLE_APPEND_WRITE (0x00000040)
+#define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS (0x00000080)
+
#define EFI_VARIABLE_MASK \
(EFI_VARIABLE_NON_VOLATILE | \
EFI_VARIABLE_BOOTSERVICE_ACCESS | \
EFI_VARIABLE_RUNTIME_ACCESS | \
EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
- EFI_VARIABLE_APPEND_WRITE)
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
+ EFI_VARIABLE_APPEND_WRITE | \
+ EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS)
/**
* Parameter structure for SetVariable and GetVariable.
@@ -142,5 +151,16 @@ typedef struct {
uint64_t VariablePayloadSize;
} SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE;
+/**
+ * Authentication header included at the start of variable data for SetVariable operations
+ * when the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set.
+ */
+typedef struct {
+ EFI_TIME TimeStamp;
+ WIN_CERTIFICATE_UEFI_GUID AuthInfo;
+} EFI_VARIABLE_AUTHENTICATION_2;
+
+#define EFI_VARIABLE_AUTHENTICATION_2_SIZE_WITHOUT_CERTDATA \
+ offsetof(EFI_VARIABLE_AUTHENTICATION_2, AuthInfo.CertData)
#endif /* TS_SMM_VARIABLE_PARAMETERS_H */
diff --git a/protocols/service/smm_variable/smm_variable_proto.h b/protocols/service/smm_variable/smm_variable_proto.h
index a47be1087..a42ff061c 100644
--- a/protocols/service/smm_variable/smm_variable_proto.h
+++ b/protocols/service/smm_variable/smm_variable_proto.h
@@ -14,4 +14,6 @@
#define SMM_VARIABLE_GUID \
{0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 }}
+#define SMM_VARIABLE_CANONICAL_GUID "ed32d533-99e6-4209-9cc0-2d72cdd998a7"
+
#endif /* TS_SMM_VARIABLE_PROTO_H */
diff --git a/protocols/test_api/fw-test-api.yaml b/protocols/test_api/fw-test-api.yaml
new file mode 100644
index 000000000..d21a41121
--- /dev/null
+++ b/protocols/test_api/fw-test-api.yaml
@@ -0,0 +1,94 @@
+openapi: "3.1.0"
+info:
+ title: Firmware Test API
+ description: |
+ A public API for testing and experimenting with Arm firmware features.
+
+ Copyright 2023, Arm Limited and Contributors. All rights reserved.
+ version: 0.0.1
+ license:
+ name: 3-Clause BSD
+ identifier: BSD-3-Clause
+
+servers:
+ - url: http://127.0.0.1/api/v1
+
+paths:
+ /services:
+ get:
+ operationId: "listServices"
+ summary: List firmware service information
+ responses:
+ '200':
+ description: A list of serviceInfo objects
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: "#/components/schemas/ServiceInfo"
+
+ /services/{servicename}:
+ get:
+ operationId: "getServiceInfo"
+ summary: Get information about a firmware service
+ parameters:
+ - name: servicename
+ in: path
+ description: e.g. fwu, crypto
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Information about the named service
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ServiceInfo'
+
+ /services/{servicename}/call/{opcode}:
+ put:
+ operationId: "callServiceOp"
+ summary: Call service operation
+ parameters:
+ - name: servicename
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: opcode
+ in: path
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Call parameters
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ '200':
+ description: Call response
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+
+components:
+ schemas:
+ ServiceInfo:
+ type: object
+ properties:
+ id:
+ type: string
+ description: The services's unique id
+ servicename:
+ type: string
+ description: Service name
+ status:
+ type: string
+ description: Service status
diff --git a/requirements.txt b/requirements.txt
index 7017f69f6..80d5b4b1a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -13,5 +13,11 @@
# Include packages needed for build test tool
-r tools/b-test/requirements.txt
+# Include packages needed for custom Python tools
+-r tools/python/requirements.txt
+
# Include c-picker needed for firmware-test-builder
git+https://git.trustedfirmware.org/TS/trusted-services.git@topics/c-picker
+
+# codespell needed for checkpatch
+codespell==2.1.0
diff --git a/tools/b-test/Makefile b/tools/b-test/Makefile
index d90f926c4..a6865a0fa 100644
--- a/tools/b-test/Makefile
+++ b/tools/b-test/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -12,23 +12,53 @@
TEMPLATES:=$(wildcard *.j2)
OUTPUTS:=$(TEMPLATES:%.j2=%)
+FILTER_PATTERN ?=
+
+ifneq (,${FILTER_PATTERN})
+RUN_SH_ARGS += -p "${FILTER_PATTERN}"
+endif
+
+ifneq (,${INSTALL_PREFIX})
+RUN_SH_ARGS += -i ${INSTALL_PREFIX}
+endif
+
+ifneq (,${BUILD_PREFIX})
+RUN_SH_ARGS += -b ${BUILD_PREFIX}
+endif
+
+ifneq (,${LOGDIR_ROOT})
+RUN_SH_ARGS += -l ${LOGDIR_ROOT}
+endif
+
all:
${MAKE} config
- bash run.sh
+ bash run.sh ${RUN_SH_ARGS}
config: ${OUTPUTS}
list:
${MAKE} config
- bash run.sh help
+ bash run.sh ${RUN_SH_ARGS} help
# run a command of the generated script
r-%:
${MAKE} config
- bash run.sh "$*"
+ bash run.sh ${RUN_SH_ARGS} "$*"
define help_msg
*************************************************************
+Variables:
+ Variables can be passed as arguments (make <var>=<value>)
+ or be set in the environment (e.g. export <var>=<value>;
+ make ...).
+
+ BUILD_PREFIX - Directory for build directories
+ FILTER_PATTERN - grep regexp to limit test scope to tests
+ whose name matches. To see the selected tests
+ run: make FILTER_PATTERN=<pattern> list
+ INSTALL_PREFIX - Directory to install projects
+ LOGDIR_ROOT - Directory to save build logs
+
Available targets:
all - generate and run test script
config - run script generation only
diff --git a/tools/b-test/requirements.txt b/tools/b-test/requirements.txt
index 1d0415e7b..9a204a0e3 100644
--- a/tools/b-test/requirements.txt
+++ b/tools/b-test/requirements.txt
@@ -1,6 +1,6 @@
#
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
-yasha==4.4
+yasha==5.0
diff --git a/tools/b-test/run.sh.j2 b/tools/b-test/run.sh.j2
index 527482297..0651f3943 100644
--- a/tools/b-test/run.sh.j2
+++ b/tools/b-test/run.sh.j2
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Copyright (c) 2020, Arm Limited and contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -18,15 +18,48 @@ fi
# Default to non-verbose mode.
VERBOSE=${VERBOSE:-0}
+# Additional environment specific CMake flags
+CMAKE_EXTRA_FLAGS=${CMAKE_EXTRA_FLAGS:-""}
+
# Get root of TS repo.
TS_ROOT=${TS_ROOT:-$(git rev-parse --show-toplevel)}
# Number of threads to use in parallel
-NUMBER_OF_PROCESSORS=${NUMBER_OF_PROCESSORS:-$(( $(nproc) * 2 )) }
+NUMBER_OF_PROCESSORS=${NUMBER_OF_PROCESSORS:-$(( $(nproc) * 2 ))}
+
+# By default run as much as we can
+FAIL_FAST=${FAIL_FAST:-0}
+
+# Directory to install projects to.
+INSTALL_PREFIX=${INSTALL_PREFIX:-./install}
+
+# Directory to place cmake build directories to
+BUILD_PREFIX=${BUILD_PREFIX:-.}
+
+# Global exit code.
+exit_code=0
+
+# List of supported tests.
+test_list=(
+{% for config in data %}
+ "{{config.name}}"
+{% endfor %}
+)
# Convert test name to build directory
function name-to-bdir() {
- printf "./build-%s" "$1"
+ printf "$BUILD_PREFIX/build-%s" "$1"
+}
+
+unset btest_logdir_root
+function name-to-logfile {
+ local config_name="$1"
+ if [ -z "$btest_logdir_root" ]
+ then
+ printf "%s/build.log" $(name-to-bdir "$1")
+ else
+ printf "$btest_logdir_root/build-%s.log" "$1"
+ fi
}
# Wrap cmake to allow verbose vs non-verbose mode
@@ -52,13 +85,13 @@ function _cmake() {
if [ "$OS_ID" != "{{config.os_id}}" ]
then
echo "Test case is not supported on this host."
- echo "########################## $COLOR_YELOW {{config.name}} skipped $COLOR_RESET"
+ echo "########################## $COLOR_YELLOW {{config.name}} skipped $COLOR_RESET"
echo "##################################################################"
return
fi
{% endif %}
b_dir=$(name-to-bdir "{{config.name}}")
- log_file=$b_dir/build.log
+ log_file=$(name-to-logfile "{{config.name}}")
rm -rf "$b_dir"
mkdir -p "$b_dir"
@@ -67,27 +100,33 @@ function _cmake() {
ccache_option=-DCMAKE_C_COMPILER_LAUNCHER=$_ccache
fi
- _cmake "$log_file" -S {{config.src}} -B "$b_dir" $ccache_option {% for param in config.params %} "{{param}}" {%endfor%} || {
-
- echo "For details see: $log_file"
- echo "########################## $COLOR_RED {{config.name}} failed $COLOR_RESET"
- return
- }
+ local retval=0
- if _cmake "$log_file" --build "$b_dir" -j ${NUMBER_OF_PROCESSORS} --verbose
+ # jinja2 is removing single newlines. Adding a comment stops this behavior.
+ if _cmake "$log_file" -S "{{config.src}}" -B "$b_dir" $ccache_option {% for param in config.params %} "{{param}}" {% endfor %} ${CMAKE_EXTRA_FLAGS} #keep newline
then
- if _cmake "$log_file" --install "$b_dir" --prefix ./install
+ if _cmake "$log_file" --build "$b_dir" -j "${NUMBER_OF_PROCESSORS}" --verbose
then
- echo "########################## $COLOR_GREEN {{config.name}} passed $COLOR_RESET"
+ if _cmake "$log_file" --install "$b_dir" --prefix "$INSTALL_PREFIX"
+ then
+ echo "########################## $COLOR_GREEN {{config.name}} passed $COLOR_RESET"
+ else
+ retval=$?
+ echo "For details see: $log_file"
+ echo "########################## $COLOR_RED {{config.name}} failed $COLOR_RESET"
+ fi
else
+ retval=$?
echo "For details see: $log_file"
echo "########################## $COLOR_RED {{config.name}} failed $COLOR_RESET"
fi
else
+ retval=$?
echo "For details see: $log_file"
echo "########################## $COLOR_RED {{config.name}} failed $COLOR_RESET"
fi
echo "##################################################################"
+ return $retval
}
{% endfor %}
@@ -99,7 +138,7 @@ do_clean() {
if [ -d "$b_dir" ]
then
echo "Removing $b_dir"
- rm -rf "$b_dir" || true
+ rm -rf "$b_dir"
fi
{% endfor %}
}
@@ -111,71 +150,232 @@ Build test runner
=================
Invocation::
- ``$0 <command>``
+ ``$0 [<options>] [<command>]``
The file "user.env" is sourced from the current directory. Use it to set
environment specific defaults. For config variables see the start of this script
and any "$<XXXX>" in the "params" array of any command in test_data.yaml
Some variables to note
- - VERBOSE : make the script output more info.
- VERBOSE=$VERBOSE
- - TS_ROOT : Root directory of the TS repo.
- TS_ROOT=$TS_ROOT
- - NUMBER_OF_PROCESSORS: number of processors in the system. Used for setting the number of
- parallel processes during build
- NUMBER_OF_PROCESSORS=$NUMBER_OF_PROCESSORS
- - SP_DEV_KIT_DIR : location of OP-TEE OS SPDEVKIT export.
- SP_DEV_KIT_DIR=$SP_DEV_KIT_DIR
-
-Available commands:
- "" - no command/default -> run all test cases
- clean - remove build directories
- help - print this text
- <test case> - run a single build
- available test cases:
- {% for config in data %}
- {{config.name}}
- {% endfor %}
+ - VERBOSE : <0/1> make the script output more info.
+ VERBOSE=$VERBOSE
+ - TS_ROOT : Root directory of the TS repo.
+ TS_ROOT=$TS_ROOT
+ - NUMBER_OF_PROCESSORS: number of processors in the system. Used for setting
+ the number of parallel processes during build
+ NUMBER_OF_PROCESSORS=$NUMBER_OF_PROCESSORS
+ - CMAKE_EXTRA_FLAGS: additional environment specific CMake flags
+ CMAKE_EXTRA_FLAGS=-DNEWLIB_LIBC_PATH=/path/to/newlib
+ - FAIL_FAST: <0/1> see -f
+ FAIL_FAST=$FAIL_FAST
+ - INSTALL_PREFIX: <path> see -i
+ INSTALL_PREFIX=$INSTALL_PREFIX
+ - BUILD_PREFIX: <path> see -b
+ BUILD_PREFIX=$BUILD_PREFIX
+
+Options:
+ -b|--build-prefix: <path>
+ - directory for cmake build directories
+ --color|--no-color
+ - force or disable output coloring
+ -f|--fail-fast
+ - exit after the first test failure
+ -i|--install-prefix <path>
+ - directory to install build results to.
+ -l|--log-dir <path>
+ - directory to save log files to. If not set, files are saved
+ to the build directory.
+ -p <regexp>
+ - filter out all test cases whose name is not matching regexp.
+ regexp is a regular expression understood by grep
+Commands:
+ "" - no command/default -> run all test cases
+ clean - remove build directories
+ help - print this text
+ <test case> - run the specified test. This can be specified multiple times
+ to allow running a list of tests.
+ available test cases $([ -n "$pattern" ] && echo "( matching '$pattern' )"):
+ $(echo "${test_list[@]}" | sed "s/ /\n /g")
END_HELP
}
+set_color_mode() {
+ _tput=$(which tput 2>/dev/null) || true "never mind"
+
+ local mode="$1"
+
+ [ "$mode" = "auto" ] || [ "$mode" = "on" ] || [ "$mode" = "off" ] || {
+ echo "ERROR: invalid argument. Valid values are auto, on and off."
+ return 1
+ }
+
+
+ # If requested mode is on, but cannot use colors, fail with an error.
+ [ -z "$_tput" ] && [ "$mode" = "on" ] && {
+ echo "set_color_mode(), ERROR: command tput can not be found, failed to force colors to on."
+ return 1
+ }
+
+ # If tput is not available turn colors off
+ [ -z "$_tput" ] && mode="off"
+
+ # If mode == auto and running in a terminal, turn colors on
+ [ "$mode" = "auto" ] && [ -t 0 ] && mode="on"
+
+
+ # By default enable colored output if tput is present and running in a terminal
+ if [ "$mode" = "on" ]
+ then
+ COLOR_YELLOW=$(tput setaf 3)
+ COLOR_RESET=$(tput sgr0)
+ COLOR_RED=$(tput setaf 1)
+ COLOR_GREEN=$(tput setaf 2)
+ else
+ COLOR_YELLOW=
+ COLOR_RESET=
+ COLOR_RED=
+ COLOR_GREEN=
+ fi
+
+ return 0
+}
+
#################### Entry point ###################################
OS_ID=$(uname -o )
-if [ -n $(which tput) -a -t ]
-then
- COLOR_YELOW=$(tput setaf 3)
- COLOR_RESET=$(tput sgr0)
- COLOR_RED=$(tput setaf 1)
- COLOR_GREEN=$(tput setaf 2)
-else
- COLOR_YELOW=
- COLOR_RESET=
- COLOR_RED=
- COLOR_GREEN=
-fi
+set_color_mode "auto"
-_ccache=$(which ccache)
+_ccache=$(which ccache 2>/dev/null) || true "never mind"
-case $1 in
- {% for config in data %}
- {{config.name}})
- {{config.name}}
- ;;
- {% endfor %}
- clean)
- do_clean
- ;;
- help)
- do_help
- ;;
- "")
- {% for config in data %}
- {{config.name}}
- {% endfor %}
- ;;
- *)
- do_help
- ;;
-esac
+process_commands() {
+ local exit_code=0
+ while true
+ do
+ case $1 in
+ {% for config in data %}
+ {{config.name}})
+ {{config.name}} || {
+ exit_code=$?
+ [ "$FAIL_FAST" -ne 0 ] && break
+ }
+ ;;
+ {% endfor %}
+ clean)
+ do_clean || {
+ exit_code=$?
+ break
+ }
+ ;;
+ help)
+ do_help
+ break
+ ;;
+ "")
+ for _test in "${test_list[@]}"
+ do
+ "$_test" || {
+ exit_code=$?
+ [ "$FAIL_FAST" -ne 0 ] && break
+ }
+ done
+ break
+ ;;
+ *)
+ echo "${COLOR_RED}Error: invalid command: $1 $COLOR_RESET"
+ do_help
+ exit_code=1
+ break
+ ;;
+ esac
+ shift
+ [ 0 -eq $# ] && break
+ done
+ return $exit_code
+}
+
+while true
+do
+ # parse options
+ arg=$1
+ case $arg in
+ -p)
+ shift
+ pattern=$1
+ if [ -z "$pattern" ]
+ then
+ echo "${COLOR_RED}Error: missing argument <search regexp>. $COLOR_RESET"
+ exit_code=1
+ break
+ else
+ readarray -t test_list < <(printf "%s\n" "${test_list[@]}" | grep -- "$pattern")
+ {% raw %}
+ [ 0 -eq ${#test_list[@]} ] && {
+ {% endraw %}
+ echo "${COLOR_RED}Error: -p <regexp> matches no tests. $COLOR_RESET"
+ exit_code=1
+ break
+ }
+ fi
+ ;;
+ --no-color)
+ set_color_mode "off"
+ ;;
+ --color)
+ set_color_mode "on"
+ ;;
+ -f|--fail-fast)
+ FAIL_FAST=1
+ ;;
+ -l|--log-dir)
+ shift
+ btest_logdir_root=$1
+ [ -z "$btest_logdir_root" ] && {
+ echo "${COLOR_RED}Error: missing argument <path>. $COLOR_RESET"
+ exit_code=1
+ break
+ }
+
+ [ -d "$btest_logdir_root" ] || {
+ mkdir -p "$btest_logdir_root"
+ }
+ ;;
+ -i|--install-prefix)
+ shift
+ INSTALL_PREFIX="$1"
+ [ -z "$INSTALL_PREFIX" ] && {
+ echo "${COLOR_RED}Error: missing argument <path> after $arg. $COLOR_RESET"
+ exit_code=1
+ break
+ }
+
+ [ -d "$INSTALL_PREFIX" ] || {
+ echo "${COLOR_RED}Error: install directory $INSTALL_PREFIX can not be found. $COLOR_RESET"
+ exit_code=1
+ break
+ }
+ ;;
+ -b|--build-prefix)
+ shift
+ BUILD_PREFIX="$1"
+ [ -z "$BUILD_PREFIX" ] && {
+ echo "${COLOR_RED}Error: missing argument <path> after $arg. $COLOR_RESET"
+ exit_code=1
+ break
+ }
+
+ [ -d "$BUILD_PREFIX" ] || {
+ echo "${COLOR_RED}Error: build directory $BUILD_PREFIX can not be found. $COLOR_RESET"
+ exit_code=1
+ break
+ }
+ ;;
+ *)
+ # parse commands
+ process_commands "$@" || exit_code=$?
+ break
+ ;;
+ esac
+ shift
+done
+
+exit $exit_code
diff --git a/tools/b-test/test_data.yaml b/tools/b-test/test_data.yaml
index 11f8f6332..57d1c6239 100644
--- a/tools/b-test/test_data.yaml
+++ b/tools/b-test/test_data.yaml
@@ -1,165 +1,249 @@
#
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
$schema: ./test_data.schema.json,
data:
- - name: "attestation-optee-arm"
- src: "$TS_ROOT/deployments/attestation/opteesp"
+ - name: "attestation-default-opteesp"
+ src: "$TS_ROOT/deployments/attestation/config/default-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "attestation-default-sp"
+ src: "$TS_ROOT/deployments/attestation/config/default-sp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "block-storage-cfi-flash-optee"
+ src: "$TS_ROOT/deployments/block-storage/config/cfi-flash-optee"
+ params:
+ - "-GUnix Makefiles"
+ - name: "block-storage-default-opteesp"
+ src: "$TS_ROOT/deployments/block-storage/config/default-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "block-storage-default-sp"
+ src: "$TS_ROOT/deployments/block-storage/config/default-sp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "block-storage-edk2-secure-flash-opteesp"
+ src: "$TS_ROOT/deployments/block-storage/config/edk2-secure-flash-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "block-storage-semihosted-opteesp"
+ src: "$TS_ROOT/deployments/block-storage/config/semihosted-opteesp"
params:
- "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- name: "component-test-arm-linux"
src: "$TS_ROOT/deployments/component-test/arm-linux"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
- - name: "component-test-pc-linux"
- os_id : "GNU/Linux"
+ - "-GUnix Makefiles"
+ - name: "component-test-linux-pc"
src: "$TS_ROOT/deployments/component-test/linux-pc"
+ os_id : "GNU/Linux"
+ params:
+ - "-GUnix Makefiles"
+ - name: "crypto-default-opteesp"
+ src: "$TS_ROOT/deployments/crypto/config/default-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "crypto-default-sp"
+ src: "$TS_ROOT/deployments/crypto/config/default-sp"
params:
- - "-GUnix Makefiles"
- - name: "crypto-optee-arm"
- src: "$TS_ROOT/deployments/crypto/opteesp"
+ - "-GUnix Makefiles"
+ - name: "env-test-baremetal-fvp_base_revc-opteesp"
+ src: "$TS_ROOT/deployments/env-test/config/baremetal-fvp_base_revc-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "env-test-baremetal-fvp_base_revc-sp"
+ src: "$TS_ROOT/deployments/env-test/config/baremetal-fvp_base_revc-sp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "env-test-n1sdp-opteesp"
+ src: "$TS_ROOT/deployments/env-test/config/n1sdp-opteesp"
params:
- - "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- - name: "env-test-optee-arm"
- src: "$TS_ROOT/deployments/env-test/opteesp"
+ - "-GUnix Makefiles"
+ - name: "fwu-tool-linux-pc"
+ src: "$TS_ROOT/deployments/fwu-tool/linux-pc"
+ os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- - name: "internal-trusted-storage-optee-arm"
- src: "$TS_ROOT/deployments/internal-trusted-storage/opteesp"
+ - "-GUnix Makefiles"
+ - name: "fwu-default-opteesp"
+ src: "$TS_ROOT/deployments/fwu/config/default-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "fwu-default-sp"
+ src: "$TS_ROOT/deployments/fwu/config/default-sp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "internal-trusted-storage-default-opteesp"
+ src: "$TS_ROOT/deployments/internal-trusted-storage/config/default-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "internal-trusted-storage-default-sp"
+ src: "$TS_ROOT/deployments/internal-trusted-storage/config/default-sp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "internal-trusted-storage-shared-flash-opteesp"
+ src: "$TS_ROOT/deployments/internal-trusted-storage/config/shared-flash-opteesp"
params:
- "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- - "-DCMAKE_VERBOSE_MAKEFILE=y"
- name: "libsp-linux-pc"
src: "$TS_ROOT/deployments/libsp/linux-pc"
os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- - name: "libsp-optee-arm"
+ - name: "libsp-opteesp"
src: "$TS_ROOT/deployments/libsp/opteesp"
params:
- "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- name: "libts-arm-linux"
src: "$TS_ROOT/deployments/libts/arm-linux"
os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- - name: "libts-pc-linux"
+ - name: "libts-linux-pc"
src: "$TS_ROOT/deployments/libts/linux-pc"
os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
+ - name: "newlib-opteesp"
+ src: "$TS_ROOT/deployments/newlib/opteesp"
+ params:
+ - "-GUnix Makefiles"
- name: "platform-inspect-arm-linux"
src: "$TS_ROOT/deployments/platform-inspect/arm-linux"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
- - name: "platform-inspect-pc-linux"
+ - "-GUnix Makefiles"
+ - name: "platform-inspect-linux-pc"
src: "$TS_ROOT/deployments/platform-inspect/linux-pc"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
- - name: "protected-storage-optee-arm"
- src: "$TS_ROOT/deployments/protected-storage/opteesp"
+ - "-GUnix Makefiles"
+ - name: "protected-storage-default-opteesp"
+ src: "$TS_ROOT/deployments/protected-storage/config/default-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "protected-storage-default-sp"
+ src: "$TS_ROOT/deployments/protected-storage/config/default-sp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "protected-storage-shared-flash-opteesp"
+ src: "$TS_ROOT/deployments/protected-storage/config/shared-flash-opteesp"
params:
- "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- - "-DCMAKE_VERBOSE_MAKEFILE=y"
- name: "psa-api-test-crypto-arm-linux"
src: "$TS_ROOT/deployments/psa-api-test/crypto/arm-linux"
- os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- - name: "psa-api-test-crypto-pc-linux"
+ - name: "psa-api-test-crypto-linux-pc"
src: "$TS_ROOT/deployments/psa-api-test/crypto/linux-pc"
- os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- name: "psa-api-test-initial_attestation-arm-linux"
src: "$TS_ROOT/deployments/psa-api-test/initial_attestation/arm-linux"
- os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- - name: "psa-api-test-initial_attestation-pc-linux"
+ - name: "psa-api-test-initial_attestation-linux-pc"
src: "$TS_ROOT/deployments/psa-api-test/initial_attestation/linux-pc"
- os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- name: "psa-api-test-internal_trusted_storage-arm-linux"
src: "$TS_ROOT/deployments/psa-api-test/internal_trusted_storage/arm-linux"
- os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- - name: "psa-api-test-internal_trusted_storage-pc-linux"
+ - name: "psa-api-test-internal_trusted_storage-linux-pc"
src: "$TS_ROOT/deployments/psa-api-test/internal_trusted_storage/linux-pc"
- os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- name: "psa-api-test-protected_storage-arm-linux"
src: "$TS_ROOT/deployments/psa-api-test/protected_storage/arm-linux"
- os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- - name: "psa-api-test-protected_storage-pc-linux"
+ - name: "psa-api-test-protected_storage-linux-pc"
src: "$TS_ROOT/deployments/psa-api-test/protected_storage/linux-pc"
+ params:
+ - "-GUnix Makefiles"
+ - name: "se-proxy-corstone1000-opteesp"
+ src: "$TS_ROOT/deployments/se-proxy/config/corstone1000-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "se-proxy-default-opteesp"
+ src: "$TS_ROOT/deployments/se-proxy/config/default-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "se-proxy-default-sp"
+ src: "$TS_ROOT/deployments/se-proxy/config/default-sp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "smm-gateway-default-opteesp"
+ src: "$TS_ROOT/deployments/smm-gateway/config/default-opteesp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "smm-gateway-default-sp"
+ src: "$TS_ROOT/deployments/smm-gateway/config/default-sp"
+ params:
+ - "-GUnix Makefiles"
+ - name: "smm-gateway-linux-pc"
+ src: "$TS_ROOT/deployments/smm-gateway/config/linux-pc"
os_id : "GNU/Linux"
params:
- "-GUnix Makefiles"
- - name: "se-proxy-optee-arm"
- src: "$TS_ROOT/deployments/se-proxy/opteesp"
+ - name: "spm-test1-opteesp"
+ src: "$TS_ROOT/deployments/spm-test1/opteesp"
params:
- "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- - name: "sfs-demo-optee-arm"
- src: "$TS_ROOT/deployments/sfs-demo/opteesp"
+ - name: "spm-test2-opteesp"
+ src: "$TS_ROOT/deployments/spm-test2/opteesp"
params:
- - "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- - name: "smm-gateway-pc-linux"
- src: "$TS_ROOT/deployments/smm-gateway/linux-pc"
+ - "-GUnix Makefiles"
+ - name: "spm-test3-opteesp"
+ src: "$TS_ROOT/deployments/spm-test3/opteesp"
params:
- "-GUnix Makefiles"
- - name: "smm-gateway-optee-arm"
- src: "$TS_ROOT/deployments/smm-gateway/opteesp"
+ - name: "spm-test4-opteesp"
+ src: "$TS_ROOT/deployments/spm-test4/opteesp"
params:
- "-GUnix Makefiles"
- - "-DSP_DEV_KIT_DIR=$SP_DEV_KIT_DIR"
- - "-DCMAKE_VERBOSE_MAKEFILE=y"
- name: "ts-demo-arm-linux"
src: "$TS_ROOT/deployments/ts-demo/arm-linux"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
- - name: "ts-demo-pc-linux"
+ - "-GUnix Makefiles"
+ - name: "ts-demo-linux-pc"
src: "$TS_ROOT/deployments/ts-demo/linux-pc"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
+ - "-GUnix Makefiles"
- name: "ts-remote-test-arm-linux"
src: "$TS_ROOT/deployments/ts-remote-test/arm-linux"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
- - name: "ts-remote-test-pc-linux"
+ - "-GUnix Makefiles"
+ - name: "ts-remote-test-linux-pc"
src: "$TS_ROOT/deployments/ts-remote-test/linux-pc"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
+ - "-GUnix Makefiles"
- name: "ts-service-test-arm-linux"
src: "$TS_ROOT/deployments/ts-service-test/arm-linux"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
- - name: "ts-service-test-pc-linux"
+ - "-GUnix Makefiles"
+ - name: "ts-service-test-linux-pc"
src: "$TS_ROOT/deployments/ts-service-test/linux-pc"
os_id : "GNU/Linux"
params:
- - "-GUnix Makefiles"
+ - "-GUnix Makefiles"
+ - name: "uefi-test-arm-linux"
+ src: "$TS_ROOT/deployments/uefi-test/arm-linux"
+ os_id : "GNU/Linux"
+ params:
+ - "-GUnix Makefiles"
+ - name: "uefi-test-linux-pc"
+ src: "$TS_ROOT/deployments/uefi-test/linux-pc"
+ os_id : "GNU/Linux"
+ params:
+ - "-GUnix Makefiles"
diff --git a/tools/bash/uefi_authenticated_variables/generate_auth_headers.sh b/tools/bash/uefi_authenticated_variables/generate_auth_headers.sh
new file mode 100755
index 000000000..47442ac39
--- /dev/null
+++ b/tools/bash/uefi_authenticated_variables/generate_auth_headers.sh
@@ -0,0 +1,153 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Relationship of the generated variable write requests:
+#
+# @startuml
+# left to right direction
+
+# rectangle PK1
+# rectangle PK2
+# rectangle PK3
+# rectangle KEK
+# rectangle db1
+# rectangle db2
+# rectangle var
+
+# PK1 --> PK1 : delete
+# PK1 --> PK2
+# PK1 --> KEK
+# PK1 --> db2
+# PK2 --> PK2 : delete
+# PK1 --> KEK : delete
+# KEK --> db1
+# db1 --> var
+# @enduml
+
+# Check environment
+which sign-efi-sig-list || { echo "Please install 'efitools' Minimum version: 1.8.1" && exit 1; }
+which sbsign || { echo "Please install 'efitools' Minimum version: 1.8.1" && exit 1; }
+which openssl || { echo "Please install 'openssl'" && exit 1; }
+
+
+HEADER_FOLDER=auth_vectors
+TEMP_FOLDER=temp_files
+
+# Generate a certificate with a public key and it's private key file
+generate_key_cert() {
+ name=$1
+
+ openssl req -x509 -newkey rsa:2048 -subj "/CN=Test $name/" -keyout $name.key -out $name.crt -days 3650 -nodes -sha256
+
+ # Create a concatenated {CRT,KEY} PEM file and also a DER from the certificate for later use
+ cat $name.crt $name.key > $name.pem
+ openssl x509 -in $name.crt -out $name.der -outform DER
+}
+
+mkdir -p ${HEADER_FOLDER}
+mkdir -p ${TEMP_FOLDER}
+pushd ${TEMP_FOLDER}
+
+# Create signer certificates
+generate_key_cert "PK1"
+generate_key_cert "PK2"
+generate_key_cert "PK3"
+generate_key_cert "KEK"
+generate_key_cert "DB1"
+generate_key_cert "DB2"
+generate_key_cert "VAR"
+
+# Create data file for the custom variable
+cat <<EOF > var_data.txt
+The term 'trusted service' is used as a general name for a class of application that runs in an isolated
+processing environment. Other applications rely on trusted services to perform security related operations in
+a way that avoids exposing secret data beyond the isolation boundary of the environment. The word 'trusted'
+does not imply anything inherently trustworthy about a service application but rather that other applications
+put trust in the service. Meeting those trust obligations relies on a range of hardware and firmware
+implemented security measures.
+
+The Arm Application-profile (A-profile) architecture, in combination with standard firmware, provides a range
+of isolated processing environments that offer hardware-backed protection against various classes of attack.
+Because of their strong security properties, these environments are suitable for running applications that have
+access to valuable assets such as keys or sensitive user data. The goal of the Trusted Services project is
+to provide a framework in which security related services may be developed, tested and easily deployed to
+run in any of the supported environments. A core set of trusted services are implemented to provide basic
+device security functions such as cryptography and secure storage.
+
+Example isolated processing environments are:
+
+ - **Secure partitions** - secure world isolated environments managed by a secure partition manager
+ - **Trusted applications** - application environments managed by a TEE
+ - **VM backed container** - container runtime that uses a hypervisor to provide hardware backed container isolation
+
+The default reference system, used for test and development, uses the Secure Partition Manager configuration
+of OP-TEE to manage a set of secure partitions running at S-EL0. The secure partitions host service providers
+that implement PSA root-of-trust services. Services may be accessed using client-side C bindings that expose PSA
+Functional APIs. UEFI SMM services are provided by the SMM Gateway.
+EOF
+
+# Generate EFI signature list from the certificates for each keystore variable and an empty esl for delete requests
+cert-to-efi-sig-list PK1.crt PK1.esl
+cert-to-efi-sig-list PK2.crt PK2.esl
+cert-to-efi-sig-list PK3.crt PK3.esl
+cert-to-efi-sig-list KEK.crt KEK.esl
+cert-to-efi-sig-list DB1.crt DB1.esl
+cert-to-efi-sig-list DB2.crt DB2.esl
+touch NULL.esl
+
+# Add another signature list before the correct KEK list to test if multiple lists are supported
+cat PK3.esl KEK.esl > KEK_concatenated.esl
+
+sign-efi-sig-list -c PK1.crt -k PK1.key PK PK1.esl PK1.auth
+sign-efi-sig-list -c PK1.crt -k PK1.key PK PK2.esl PK2.auth
+sign-efi-sig-list -c PK3.crt -k PK3.key PK PK3.esl PK3.auth
+sign-efi-sig-list -c PK1.crt -k PK1.key PK NULL.esl PK1_delete.auth
+sign-efi-sig-list -c PK2.crt -k PK2.key PK NULL.esl PK2_delete.auth
+sign-efi-sig-list -c PK1.crt -k PK1.key KEK KEK_concatenated.esl KEK.auth
+sign-efi-sig-list -c PK1.crt -k PK1.key KEK NULL.esl KEK_delete.auth
+sign-efi-sig-list -c KEK.crt -k KEK.key db DB1.esl DB1.auth
+sign-efi-sig-list -c PK1.crt -k PK1.key db DB2.esl DB2.auth
+# GUID: Must be syncronized with m_common_guid in the tests
+sign-efi-sig-list -c DB1.crt -k DB1.key -g '01234567-89AB-CDEF-0123-456789ABCDEF' var var_data.txt VAR.auth
+sign-efi-sig-list -c DB1.crt -k DB1.key -g '01234567-89AB-CDEF-0123-456789ABCDEF' var /dev/null VAR_delete.auth
+
+# Generate C headers from the authentication headers for the tests
+xxd -i PK1.auth > ../${HEADER_FOLDER}/PK1.h
+xxd -i PK2.auth > ../${HEADER_FOLDER}/PK2.h
+xxd -i PK3.auth > ../${HEADER_FOLDER}/PK3.h
+xxd -i PK1_delete.auth > ../${HEADER_FOLDER}/PK1_delete.h
+xxd -i PK2_delete.auth > ../${HEADER_FOLDER}/PK2_delete.h
+xxd -i KEK.auth > ../${HEADER_FOLDER}/KEK.h
+xxd -i KEK_delete.auth > ../${HEADER_FOLDER}/KEK_delete.h
+xxd -i DB1.auth > ../${HEADER_FOLDER}/db1.h
+xxd -i DB2.auth > ../${HEADER_FOLDER}/db2.h
+xxd -i VAR.auth > ../${HEADER_FOLDER}/var.h
+xxd -i VAR_delete.auth > ../${HEADER_FOLDER}/var_delete.h
+xxd -i var_data.txt > ../${HEADER_FOLDER}/var_data.h
+
+popd
+
+# Add copyright to the beginning of the headers
+current_year=$(date +"%Y")
+copyright_header=$(cat <<-END
+/*
+ * Copyright (c) ${current_year}, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file was generated by generate_auth_headers.sh
+ */
+END
+)
+
+for file in ./${HEADER_FOLDER}/*
+do
+ if test -f "$file"
+ then
+ echo -e "${copyright_header}\n\n$(cat $file)" > $file
+ fi
+done
diff --git a/tools/cmake/common/AddComponents.cmake b/tools/cmake/common/AddComponents.cmake
index 07978bb3a..479f145de 100644
--- a/tools/cmake/common/AddComponents.cmake
+++ b/tools/cmake/common/AddComponents.cmake
@@ -1,5 +1,4 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -50,11 +49,20 @@ function(add_components)
set(MY_PARAMS_BASE_DIR "${MY_PARAMS_BASE_DIR}/")
endif()
- set(TGT ${MY_PARAMS_TARGET} CACHE STRING "")
+ set(TGT ${MY_PARAMS_TARGET})
foreach(_comp IN ITEMS ${MY_PARAMS_COMPONENTS})
set(_file ${MY_PARAMS_BASE_DIR}${_comp}/component.cmake)
include(${_file})
set(CMAKE_CONFIGURE_DEPENDS ${_file})
endforeach()
- unset(TGT CACHE)
+ # Remove duplicate settings
+ foreach(_prop IN ITEMS INTERFACE_INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES
+ INTERFACE_COMPILE_DEFINITIONS COMPILE_DEFINITIONS
+ INTERFACE_COMPILE_OPTIONS COMPILE_OPTIONS
+ INTERFACE_SOURCES SOURCES
+ PUBLIC_HEADER)
+ get_property(_tmp TARGET ${MY_PARAMS_TARGET} PROPERTY ${_prop})
+ list(REMOVE_DUPLICATES _tmp)
+ set_property(TARGET ${MY_PARAMS_TARGET} PROPERTY ${_prop} ${_tmp})
+ endforeach()
endfunction()
diff --git a/tools/cmake/common/AddPlatform.cmake b/tools/cmake/common/AddPlatform.cmake
index ae34c6e4c..37efdf2fa 100644
--- a/tools/cmake/common/AddPlatform.cmake
+++ b/tools/cmake/common/AddPlatform.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -24,6 +24,10 @@ Add platform provided components to a build
``TARGET``
The name of an already defined target to add platform components to.
+ ``TS_PLATFORM``
+ This global variable is used to construct a path to the platform specific cmake file.
+ :variable:TS_PLATFORM can be set from the command line and the value must be lower case.
+
#]===]
function(add_platform)
set(options )
@@ -34,12 +38,12 @@ function(add_platform)
message(FATAL_ERROR "add_platform: mandatory parameter TARGET not defined!")
endif()
- set(TGT ${MY_PARAMS_TARGET} CACHE STRING "")
-
# Ensure file path conforms to lowercase project convention
- string(TOLOWER "${TS_PLATFORM_ROOT}/${TS_PLATFORM}/platform.cmake" _platdef)
- include(${_platdef})
- set(CMAKE_CONFIGURE_DEPENDS ${_platdef})
-
- unset(TGT CACHE)
+ string(TOLOWER "${TS_PLATFORM}" _tmp)
+ if (NOT "${TS_PLATFORM}" STREQUAL "${_tmp}")
+ message(FATAL_ERROR "Value of TS_PLATFORM may only use lowercase letters. The current value"
+ " \"${TS_PLATFORM}\" violates this.")
+ endif()
+ set(TGT ${MY_PARAMS_TARGET})
+ include(${TS_PLATFORM_ROOT}/${TS_PLATFORM}/platform.cmake)
endfunction()
diff --git a/tools/cmake/common/ExportLibrary.cmake b/tools/cmake/common/ExportLibrary.cmake
index fed4e75c5..c171c5b16 100644
--- a/tools/cmake/common/ExportLibrary.cmake
+++ b/tools/cmake/common/ExportLibrary.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -10,7 +10,7 @@
.. code:: cmake
- export_library(TARGET LIB_NAME INTERFACE_FILES)
+ export_library(TARGET <target name> LIB_NAME <library name> PKG_CONFIG_FILE <file name>)
INPUTS:
@@ -20,24 +20,31 @@
``LIB_NAME``
The name of the library.
- ``INTERFACE_FILES``
- List of header files to declare the library's public interface.
+ ``PKG_CONFIG_FILE``
+ Name of the package configuration file to generate.
#]===]
function(export_library)
set(options )
- set(oneValueArgs TARGET LIB_NAME)
- set(multiValueArgs INTERFACE_FILES)
+ set(oneValueArgs TARGET LIB_NAME PKG_CONFIG_FILE)
+ set(multiValueArgs)
cmake_parse_arguments(MY_PARAMS "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
- if(NOT DEFINED MY_PARAMS_TARGET)
- message(FATAL_ERROR "export_library: mandatory parameter TARGET not defined!")
- endif()
- if(NOT DEFINED MY_PARAMS_LIB_NAME)
- message(FATAL_ERROR "export_library: mandatory parameter LIB_NAME not defined!")
+ foreach(_param IN ITEMS MY_PARAMS_TARGET MY_PARAMS_LIB_NAME MY_PARAMS_PKG_CONFIG_FILE)
+ if(NOT DEFINED ${_param})
+ list(APPEND _miss_params "${_param}" )
+ endif()
+ endforeach()
+
+ if (_miss_params)
+ string(REPLACE ";" ", " _miss_params "${_miss_params}")
+ message(FATAL_ERROR "export_library: mandatory parameter(s) ${_miss_params} not defined!")
endif()
+
+ string(TOLOWER "${MY_PARAMS_LIB_NAME}" LC_LIB_NAME)
+
# Set default install location if none specified
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
@@ -55,18 +62,56 @@ function(export_library)
DESTINATION ${TS_ENV}/include
)
- # Install library header files files
- install(
- FILES ${MY_PARAMS_INTERFACE_FILES}
- DESTINATION ${TS_ENV}/include
+ # Create targets file.
+ export(
+ EXPORT
+ ${MY_PARAMS_LIB_NAME}_targets
+ FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/${MY_PARAMS_LIB_NAME}Targets.cmake"
+ NAMESPACE
+ ${MY_PARAMS_LIB_NAME}::
+ )
+
+ # Create a config file package.
+ include(CMakePackageConfigHelpers)
+ get_target_property(_ver ${MY_PARAMS_TARGET} VERSION)
+ write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/${LC_LIB_NAME}ConfigVersion.cmake"
+ VERSION "${_ver}"
+ COMPATIBILITY SameMajorVersion
+ )
+
+ # Finalize config file.
+ # Config package location relative to install root.
+ set(ConfigPackageLocation ${TS_ENV}/lib/cmake/${MY_PARAMS_LIB_NAME})
+
+ get_filename_component(_configured_pkgcfg_name "${MY_PARAMS_PKG_CONFIG_FILE}" NAME_WLE)
+ set(_configured_pkgcfg_name "${CMAKE_CURRENT_BINARY_DIR}/${_configured_pkgcfg_name}")
+ configure_package_config_file(
+ "${MY_PARAMS_PKG_CONFIG_FILE}"
+ "${_configured_pkgcfg_name}"
+ INSTALL_DESTINATION
+ ${ConfigPackageLocation}
)
# Install the export details
install(
EXPORT ${MY_PARAMS_LIB_NAME}_targets
- FILE ${MY_PARAMS_LIB_NAME}_targets.cmake
+ FILE ${MY_PARAMS_LIB_NAME}Targets.cmake
NAMESPACE ${MY_PARAMS_LIB_NAME}::
- DESTINATION ${TS_ENV}/lib/cmake
+ DESTINATION ${ConfigPackageLocation}
COMPONENT ${MY_PARAMS_LIB_NAME}
)
+
+
+ # install config and version files
+ install(
+ FILES
+ "${_configured_pkgcfg_name}"
+ "${CMAKE_CURRENT_BINARY_DIR}/${LC_LIB_NAME}ConfigVersion.cmake"
+ DESTINATION
+ ${ConfigPackageLocation}
+ COMPONENT
+ ${MY_PARAMS_LIB_NAME}
+ )
endfunction()
diff --git a/tools/cmake/common/ExportMemoryRegionsToManifest.cmake b/tools/cmake/common/ExportMemoryRegionsToManifest.cmake
new file mode 100644
index 000000000..affd74633
--- /dev/null
+++ b/tools/cmake/common/ExportMemoryRegionsToManifest.cmake
@@ -0,0 +1,46 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#[===[.rst:
+.. cmake:command:: export_memory_regions_to_manifest
+
+ Exports the memory regions from an ELF format SP into a manifest file fragment.
+
+ .. code:: cmake
+
+ export_memory_regions_to_manifest(TARGET NAME RES)
+
+ INPUTS:
+
+ ``TARGET``
+ Build target
+
+ ``NAME``
+ The UUID of the SP as a string.
+
+ ``RES``
+ The name of the SP.
+
+#]===]
+function(export_memory_regions_to_manifest)
+ set(options)
+ set(oneValueArgs TARGET NAME RES)
+ set(multiValueArgs)
+ cmake_parse_arguments(MY "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN} )
+
+ find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+ add_custom_command(
+ TARGET ${MY_TARGET} POST_BUILD
+ COMMAND ${Python3_EXECUTABLE} ${TS_ROOT}/tools/python/elf_segments_to_manifest.py
+ $<TARGET_FILE:${MY_TARGET}>
+ $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME})
+ if (MY_RES)
+ set(${MY_RES} $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME} PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/tools/cmake/common/ExportSp.cmake b/tools/cmake/common/ExportSp.cmake
new file mode 100644
index 000000000..78701b933
--- /dev/null
+++ b/tools/cmake/common/ExportSp.cmake
@@ -0,0 +1,117 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+include(${CMAKE_CURRENT_LIST_DIR}/Uuid.cmake)
+
+#[===[.rst:
+.. cmake:command:: export_sp
+
+ .. code:: cmake
+
+ export_sp(
+ SP_FFA_UUID_CANON <uuid_str_canon>
+ SP_NAME <name> MK_IN <.mk path>
+ DTS_IN <DTS path>
+ DTS_MEM_REGIONS <Memory region manifest path>
+ JSON_IN <JSON path>
+ )
+
+ INPUTS:
+
+ ``SP_FFA_UUID_CANON``
+ The FF-A UUID of the SP as a canonical string.
+
+ ``SP_BIN_UUID_CANON``
+ The UUID of the SP binary a canonical string. When not set use the
+ SP_FFA_UUID_CANON as the SP_BIN_UUID_CANON.
+
+ ``SP_NAME``
+ The name of the SP.
+
+ ``MK_IN``
+ Optional, Makefile template for OP-TEE build
+
+ ``DTS_IN``
+ Manifest file template
+
+ `DTS_MEM_REGIONS`
+ Optional, Memory region manifest file
+
+ ``JSON_IN``
+ Optional, SP layout JSON file template for TF-A
+
+#]===]
+function (export_sp)
+ set(options)
+ set(oneValueArgs SP_FFA_UUID_CANON SP_BIN_UUID_CANON SP_NAME MK_IN DTS_IN DTS_MEM_REGIONS JSON_IN)
+ set(multiValueArgs)
+ cmake_parse_arguments(EXPORT "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN} )
+
+ if(NOT DEFINED EXPORT_SP_FFA_UUID_CANON)
+ message(FATAL_ERROR "export_sp: mandatory parameter SP_FFA_UUID_CANON not defined!")
+ endif()
+ if(NOT DEFINED EXPORT_SP_BIN_UUID_CANON)
+ # We use the same UUID for the binary and FF-A if the UUID of the SP binary is not set
+ set(EXPORT_SP_BIN_UUID_CANON ${EXPORT_SP_FFA_UUID_CANON})
+ endif()
+ if(NOT DEFINED EXPORT_SP_NAME)
+ message(FATAL_ERROR "export_sp: mandatory parameter SP_NAME not defined!")
+ endif()
+ if(NOT DEFINED EXPORT_DTS_IN)
+ message(FATAL_ERROR "export_sp: mandatory parameter DTS_IN not defined!")
+ endif()
+
+ if (DEFINED EXPORT_MK_IN)
+ configure_file(${EXPORT_MK_IN} ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_NAME}.mk @ONLY NEWLINE_STYLE UNIX)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_NAME}.mk DESTINATION ${TS_ENV}/lib/make)
+ endif()
+
+ # In the SP manifest DT the UUID format is four uint32 numbers (little-endian)
+ # Create a litte endian 4 digit octests representation.
+ uuid_canon_to_le_words(UUID ${EXPORT_SP_FFA_UUID_CANON} RES _le_words)
+ list(JOIN _le_words " 0x" _uuid_le)
+ set(SP_UUID_LE " 0x${_uuid_le}" PARENT_SCOPE)
+ set(EXPORT_SP_UUID_DT " 0x${_uuid_le}")
+
+ # As the .dtsi is meant to be included in .dts file, it shouldn't contain a separate
+ # /dts-v1/ tag and its node should be unique, i.e. the SP name.
+ set(DTS_TAG "")
+ set(DTS_NODE "${EXPORT_SP_NAME}")
+ configure_file(${EXPORT_DTS_IN} ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_BIN_UUID_CANON}_before_preprocessing.dtsi @ONLY NEWLINE_STYLE UNIX)
+
+ compiler_preprocess_file(
+ SRC ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_BIN_UUID_CANON}_before_preprocessing.dtsi
+ DST ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_BIN_UUID_CANON}.dtsi
+ TARGET ${EXPORT_SP_NAME}
+ )
+
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_BIN_UUID_CANON}.dtsi DESTINATION ${TS_ENV}/manifest)
+
+ # The .dts file is a standalone structure, thus it should have the /dts-v1/ tag and it
+ # starts with the root node.
+ set(DTS_TAG "/dts-v1/;")
+ set(DTS_NODE "/")
+ configure_file(${EXPORT_DTS_IN} ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_BIN_UUID_CANON}_before_preprocessing.dts @ONLY NEWLINE_STYLE UNIX)
+
+ compiler_preprocess_file(
+ SRC ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_BIN_UUID_CANON}_before_preprocessing.dts
+ DST ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_BIN_UUID_CANON}.dts
+ TARGET ${EXPORT_SP_NAME}
+ )
+
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_BIN_UUID_CANON}.dts DESTINATION ${TS_ENV}/manifest)
+
+ if (DEFINED EXPORT_DTS_MEM_REGIONS)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_DTS_MEM_REGIONS} DESTINATION ${TS_ENV}/manifest)
+ endif()
+
+ if (DEFINED EXPORT_JSON_IN)
+ configure_file(${EXPORT_JSON_IN} ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_NAME}.json @ONLY NEWLINE_STYLE UNIX)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_SP_NAME}.json DESTINATION ${TS_ENV}/json)
+ endif()
+endfunction()
diff --git a/tools/cmake/common/LazyFetch.cmake b/tools/cmake/common/LazyFetch.cmake
new file mode 100644
index 000000000..0c00bcedf
--- /dev/null
+++ b/tools/cmake/common/LazyFetch.cmake
@@ -0,0 +1,316 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Determine the number of processes to run while running parallel builds.
+# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
+if(NOT DEFINED PROCESSOR_COUNT)
+ include(ProcessorCount)
+ ProcessorCount(PROCESSOR_COUNT)
+ set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
+endif()
+
+#[===[.rst:
+Common fetch interface for external dependencies.
+-------------------------------------------------
+
+The following variables can be set in cmake or in the environment to configure various aspect of
+building and external component.
+Note: <DEP_NAME> is the name of the dependency as set int the cmake files with all characters
+converted to uppercase.
+
+``<DEP_NAME>_VERBOSE_CONFIG``
+ Global variable or environment variable.
+ Pass `--trace-expand` to cmake if set.
+
+``<DEP_NAME>_VERBOSE_BUILD``
+ Global variable or environment variable.
+ Turn the build step to verbose mode if set.
+
+``<DEP_NAME>_GENERATOR``
+ Global variable or environment variable.
+ Set the cmake generator to a specific value. If not set, the value of CMAKE_GENERATOR
+ will be used.
+#]===]
+
+#[===[.rst:
+.. cmake:command:: LazyFetch_Fetch
+
+ .. code:: cmake
+ LazyFetch_Fetch(DEP_NAME <dependency name> OPTIONS <list of options for FetchContent_Declare>)
+
+ INPUTS:
+ ``DEP_NAME``
+ Unique name for the dependency, used by FetchContent_* functions
+ ``OPTIONS``
+ List of options for FetchContent_Declare, e.g. git url and refspec, check cmake documentations for more
+ information
+ #]===]
+
+function(LazyFetch_Fetch DEP_NAME OPTIONS)
+ include(FetchContent)
+
+ # Fetching dependency
+ FetchContent_Declare(
+ ${DEP_NAME}
+ ${OPTIONS}
+ )
+
+ FetchContent_GetProperties(${DEP_NAME})
+ if(NOT "${DEP_NAME}_POPULATED")
+ message(STATUS "Fetching ${DEP_NAME}")
+ FetchContent_Populate(${DEP_NAME})
+ endif()
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: LazyFetch_ConfigAndBuild
+
+ .. code:: cmake
+ LazyFetch_ConfigAndBuild(DEP_NAME <dependency name> SRC_DIR <source code dir> BIN_DIR <binary dir>
+ CACHE_FILE <path to the initial cache file> INSTALL_DIR <install path>)
+
+ INPUTS:
+ ``DEP_NAME``
+ Unique name for the dependency
+ ``SRC_DIR``
+ Source directory
+ ``BIN_DIR``
+ Build directory
+ ``CACHE_FILE``
+ Path to the initial cache file. Setting cache variables in this file can be used to augment
+ the configure process. The file goes through :cmake:function:`configure_file(... @ONLY)`, this
+ can be used to pass variables to the external project.
+ ``INSTALL_DIR``
+ Install path. If not set, the install step will be skipped.
+ ``<DEP_NAME>_VERBOSE_CONFIG``
+ Global variable or environment variable.
+ Pass `--trace-expand` to cmake if set.
+ ``<DEP_NAME>_VERBOSE_BUILD``
+ Global variable or environment variable.
+ Turn the build step to verbose mode if set.
+ #]===]
+
+function(LazyFetch_ConfigAndBuild)
+ set(oneValueArgs DEP_NAME SRC_DIR BIN_DIR CACHE_FILE INSTALL_DIR)
+ cmake_parse_arguments(BUILD "${__options}" "${oneValueArgs}" "${_multipleValueArgs}" ${ARGN})
+ message(STATUS "Configuring and building ${BUILD_DEP_NAME}")
+
+ # Store config file in build dir, so it gets cleaned up
+ set(CONFIGURED_CACHE_FILE ${CMAKE_BINARY_DIR}/${BUILD_DEP_NAME}-init-cache.cmake)
+ configure_file(${BUILD_CACHE_FILE} ${CONFIGURED_CACHE_FILE} @ONLY)
+
+ string(TOUPPER ${BUILD_DEP_NAME} UC_DEP_NAME)
+
+ if (NOT DEFINED ${UC_DEP_NAME}_BUILD_TYPE)
+ message(FATAL_ERROR "Build type for external component ${DEP_NAME} is not set. Please pass "
+ "-D${UC_DEP_NAME}_BUILD_TYPE=<build type> to cmake. Supported build types are"
+ "component specific. Pleas refer to the upstream documentation for more information.")
+ endif()
+
+ if (DEFINED ${UC_DEP_NAME}_VERBOSE_CONFIG OR DEFINED ENV{${UC_DEP_NAME}_VERBOSE_CONFIG})
+ set(_CMAKE_VERBOSE_CFG_FLAG "--trace-expand")
+ endif()
+
+ if(NOT DEFINED ${UC_DEP_NAME}_GENERATOR)
+ if(DEFINED ENV{${UC_DEP_NAME}_GENERATOR})
+ set(${UC_DEP_NAME}_GENERATOR ENV{${UC_DEP_NAME}_GENERATOR} CACHE STRING "CMake generator used for ${UC_DEP_NAME}.")
+ else()
+ set(${UC_DEP_NAME}_GENERATOR ${CMAKE_GENERATOR} CACHE STRING "CMake generator used for ${UC_DEP_NAME}.")
+ endif()
+ endif()
+
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
+ ${CMAKE_COMMAND}
+ "-C${CONFIGURED_CACHE_FILE}"
+ -DCMAKE_BUILD_TYPE=${${UC_DEP_NAME}_BUILD_TYPE}
+ -G${${UC_DEP_NAME}_GENERATOR}
+ -S ${BUILD_SRC_DIR}
+ -B ${BUILD_BIN_DIR}
+ ${_CMAKE_VERBOSE_CFG_FLAG}
+ RESULT_VARIABLE
+ _exec_error
+ )
+ if (NOT _exec_error EQUAL 0)
+ message(FATAL_ERROR "Configuring ${BUILD_DEP_NAME} build failed. `${_exec_error}`")
+ endif()
+
+ if (DEFINED ${UC_DEP_NAME}_VERBOSE_BUILD OR DEFINED ENV{${UC_DEP_NAME}_VERBOSE_BUILD})
+ set(_CMAKE_VERBOSE_CFG_FLAG "--verbose")
+ endif()
+
+ if (BUILD_INSTALL_DIR)
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
+ ${CMAKE_COMMAND}
+ --build ${BUILD_BIN_DIR}
+ --parallel ${PROCESSOR_COUNT}
+ --target install
+ ${_CMAKE_VERBOSE_BLD_FLAG}
+ RESULT_VARIABLE
+ _exec_error
+ )
+ else()
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
+ ${CMAKE_COMMAND}
+ --build ${BUILD_BIN_DIR}
+ --parallel ${PROCESSOR_COUNT}
+ ${_CMAKE_VERBOSE_BLD_FLAG}
+ RESULT_VARIABLE
+ _exec_error
+ )
+ endif()
+ if (NOT _exec_error EQUAL 0)
+ message(FATAL_ERROR "Building ${BUILD_DEP_NAME} failed. ${_exec_error}")
+ endif()
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: LazyFetch_MakeAvailable
+
+ .. code:: cmake
+ LazyFetch_MakeAvailable(DEP_NAME <dependency name> INSTALL_DIR <install path>
+ PACKAGE_DIR <directory of moduleConfig.cmake file>
+ CACHE_FILE <path to the cache init file> FETCH_OPTIONS <options for the fetching process>)
+
+ INPUTS:
+ ``DEP_NAME``
+ If set, this path overwrites the default base path for the FetchContent process
+ ``SOURCE_DIR``
+ Location of source code.
+ ``INSTALL_DIR``
+ Build install path
+ ``PACKAGE_DIR``
+ If set find_package will search this directory for the config file
+ ``CACHE_FILE``
+ Path to the cache init file, setting cache variables in this file can be used to augment the
+ configure process. The file goes through the :cmake:function:`configure_file(... @ONLY)`, this
+ can be used to pass variables to the cache file
+ ``FETCH_OPTIONS``
+ Configure the dependency fetching process, this is passed to FetchContent_Declare, check the
+ cmake documentation for more info
+ ``SOURCE_SUBDIR``
+ A subdirectory relative to the top level directory of the fetched component, where the CMakeLists.txt file
+ can be found.
+ ``<DEP_NAME>_VERBOSE_CONFIG``
+ Global variable or environment variable.
+ Pass `--trace-expand` to cmake if set.
+ ``<DEP_NAME>_VERBOSE_BUILD``
+ Global variable or environment variable.
+ Turn the build step to verbose mode if set.
+ #]===]
+
+macro(LazyFetch_MakeAvailable)
+ set(oneValueArgs DEP_NAME SOURCE_DIR BINARY_DIR INSTALL_DIR PACKAGE_DIR CACHE_FILE SOURCE_SUBDIR)
+ set(multipleValueArgs FETCH_OPTIONS)
+ cmake_parse_arguments(MY "${__options}" "${oneValueArgs}" "${multipleValueArgs}" ${ARGN})
+ message(STATUS "Looking for dependency ${MY_DEP_NAME}")
+
+ if (NOT DEFINED MY_DEP_NAME)
+ message(FATAL_ERROR "Mandatory parameter DEP_NAME is missing.")
+ endif()
+
+ # FetchContent* functions use this form
+ string(TOLOWER ${MY_DEP_NAME} MY_LC_DEP_NAME)
+ # We also need the upper case version
+ string(TOUPPER ${MY_DEP_NAME} MY_UC_DEP_NAME)
+
+ # Look for name collision. We can collide with project() commands, other external components defined with
+ # LazyFetch, FetchCOntent or ExternalProject.
+ if(DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR AND NOT DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR_LZF)
+ string(CONCAT _msg "External dependency name \"${MY_DEP_NAME}\" collides with a project or another external"
+ " dependency name.")
+ message(FATAL_ERROR ${_msg})
+ endif()
+ # This variable is used to avoid false colision detection when re-configuring the project.
+ set(${MY_LC_DEP_NAME}_BINARY_DIR_LZF On CACHE BOOL "")
+ mark_as_advanced(${MY_LC_DEP_NAME}_BINARY_DIR_LZF)
+ # These two variables are also set by the normal FetchContent process and users could depend on them,
+ # so they are not unset at the end of the macro
+ if (MY_BINARY_DIR)
+ set(${MY_LC_DEP_NAME}_BINARY_DIR ${MY_BINARY_DIR})
+ else()
+ set(${MY_LC_DEP_NAME}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-build)
+ endif()
+ set(${MY_LC_DEP_NAME}_BINARY_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR} CACHE PATH
+ "Build directory for ${MY_LC_DEP_NAME}" FORCE)
+
+ if (MY_SOURCE_DIR)
+ set(${MY_LC_DEP_NAME}_SOURCE_DIR ${MY_SOURCE_DIR})
+ else()
+ set(${MY_LC_DEP_NAME}_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-src)
+ endif()
+ set(${MY_LC_DEP_NAME}_SOURCE_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR} CACHE PATH
+ "Source directory for ${MY_LC_DEP_NAME}" FORCE)
+
+ set(${MY_LC_DEP_NAME}_SUBBUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-subbuild CACHE
+ STRING "Sub-build directory for ${MY_LC_DEP_NAME}")
+
+ list(APPEND MY_FETCH_OPTIONS
+ SOURCE_DIR "${${MY_LC_DEP_NAME}_SOURCE_DIR}"
+ BINARY_DIR "${${MY_LC_DEP_NAME}_BINARY_DIR}"
+ SUBBUILD_DIR "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}")
+
+ if (NOT DEFINED MY_INSTALL_DIR OR NOT EXISTS ${MY_INSTALL_DIR})
+ if (NOT EXISTS ${${MY_LC_DEP_NAME}_BINARY_DIR} OR NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR})
+ if (NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR})
+ LazyFetch_Fetch(${MY_LC_DEP_NAME} "${MY_FETCH_OPTIONS}")
+ file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_BINARY_DIR}")
+ file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}")
+ endif()
+ if (MY_CACHE_FILE)
+ LazyFetch_ConfigAndBuild(
+ DEP_NAME ${MY_LC_DEP_NAME}
+ SRC_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR}/${MY_SOURCE_SUBDIR}
+ BIN_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR}
+ CACHE_FILE ${MY_CACHE_FILE}
+ INSTALL_DIR ${MY_INSTALL_DIR}
+ )
+ endif()
+ elseif(DEFINED MY_INSTALL_DIR)
+ if(DEFINED ${MY_UC_DEP_NAME}_VERBOSE_BUILD OR DEFINED ENV{${MY_UC_DEP_NAME}_VERBOSE_BUILD})
+ set(_CMAKE_VERBOSE_BLD_FLAG "--verbose")
+ endif()
+
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
+ ${CMAKE_COMMAND}
+ --build ${${MY_LC_DEP_NAME}_BINARY_DIR}
+ --parallel ${PROCESSOR_COUNT}
+ --target install
+ ${_CMAKE_VERBOSE_BLD_FLAG}
+ RESULT_VARIABLE
+ _exec_error
+ )
+ if (NOT _exec_error EQUAL 0)
+ message(FATAL_ERROR "Installing ${BUILD_DEP_NAME} failed. ${_exec_error}")
+ endif()
+ endif()
+ endif()
+
+ # Run find_package again if we just needed the build and install step
+ if (MY_PACKAGE_DIR)
+ unset(${MY_LC_DEP_NAME}_DIR)
+ unset(${MY_LC_DEP_NAME}_DIR CACHE)
+ unset(${MY_DEP_NAME}-FOUND CACHE)
+ find_package(${MY_DEP_NAME} CONFIG REQUIRED NO_DEFAULT_PATH PATHS ${MY_PACKAGE_DIR})
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MY_DEP_NAME}_CONFIG)
+ endif()
+
+ unset(MY_DEP_NAME)
+ unset(MY_SOURCE_DIR)
+ unset(MY_BINARY_DIR)
+ unset(MY_INSTALL_DIR)
+ unset(MY_PACKAGE_DIR)
+ unset(MY_CACHE_FILE)
+ unset(MY_SOURCE_SUBDIR)
+ unset(MY_FETCH_OPTIONS)
+ unset(MY_LC_DEP_NAME)
+ unset(oneValueArgs)
+ unset(multipleValueArgs)
+endmacro() \ No newline at end of file
diff --git a/tools/cmake/common/PropertyCopy.cmake b/tools/cmake/common/PropertyCopy.cmake
new file mode 100644
index 000000000..754c98ce7
--- /dev/null
+++ b/tools/cmake/common/PropertyCopy.cmake
@@ -0,0 +1,459 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#[===[.rst:
+PropertyCopy.cmake
+------------------
+
+This module allows saving interface properties of a target to a set of variables and to translate
+the variables to cmake script fragment of compiler and linker flag lists.
+The main purpose is to allow transferring settings to sub-projects which need strong separation
+(i.e. ExternalProject is used) or use a non CMake build system.
+
+For CMake projects the data-flow is to save the settings to variables, translate these to cmake code
+fragment, and then inject these to the sub-projects using a generated initial cache file.
+Alternatively translate the saved values to list variables `<PREFIX>_CMAKE_C_FLAGS_INIT` and
+`<PREFIX>_CMAKE_EXE_LINKER_FLAGS_INIT`, and pass these to the sub-project using the -D command-line
+parameter.
+
+For non CMake projects the data-flow is to save the properties to variables and the translate to
+compiler and linker argument lists. Then use the generated `<PREFIX>_CMAKE_C_FLAGS_INIT` and
+`<PREFIX>_CMAKE_EXE_LINKER_FLAGS_INIT` variables in a build system specific way (e.g. setting
+`CFLAGS` and `LDFLAGS` environment variables) to configure the sub-project.
+
+#]===]
+
+#[===[.rst:
+.. cmake:variable:: PROPERTYCOPY_DEFAULT_PROPERTY_LIST
+
+Default list of properties to save and restore. It is used by functions in this file. Some of these
+allow using a custom list instead by passing appropriate parameters.
+#]===]
+set(PROPERTYCOPY_DEFAULT_PROPERTY_LIST INTERFACE_COMPILE_DEFINITIONS
+ INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES
+ INTERFACE_LINK_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_LINK_OPTIONS
+ INTERFACE_POSITION_INDEPENDENT_CODE
+ INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
+
+#[===[.rst:
+.. cmake:command:: save_interface_target_properties
+
+ .. code-block:: cmake
+
+ save_interface_target_properties(TGT stdlib:c PREFIX LIBC)
+ save_interface_target_properties(TGT stdlib:c PREFIX LIBC
+ PROPERTIES INTERFACE_LINK_DIRECTORIES INTERFACE_LINK_LIBRARIES)
+
+ Save interface properties of a target to a set of variables. Variables are named after the
+ properties prefixed with the parameter <PREFIX>_. (i.e. FOO_INTERFACE_COMPILE_OPTIONS if the
+ prefix was "FOO").
+ The list of properties to be saved can be set using the PROPERTIES parameter. If this is not
+ set, the :variable:`PROPERTYCOPY_DEFAULT_PROPERTY_LIST` is used.
+
+ Inputs:
+ ``TGT``
+ Target to copy properties from.
+ ``PROPERTIES``
+ Optional. List of properties to save. If not set, the default list is used. See:
+ :variable:`PROPERTYCOPY_DEFAULT_PROPERTY_LIST`.
+ ``PREFIX``
+ Prefix to use for output variable names.
+ Outputs:
+ A set of variables (see description).
+#]===]
+function(save_interface_target_properties)
+ set(_OPTIONS_ARGS)
+ set(_ONE_VALUE_ARGS TGT PREFIX)
+ set(_MULTI_VALUE_ARGS PROPERTIES)
+ cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+ if (NOT DEFINED _MY_PARAMS_PREFIX)
+ message(FATAL_ERROR "Mandatory parameter PREFIX is not defined.")
+ endif()
+ if (NOT DEFINED _MY_PARAMS_TGT)
+ message(FATAL_ERROR "Mandatory parameter TGT is not defined.")
+ endif()
+ if(NOT TARGET ${_MY_PARAMS_TGT})
+ message(FATAL_ERROR "Target \"${_MY_PARAMS_TGT}\" does not exist.")
+ endif()
+ if (NOT DEFINED _MY_PARAMS_PROPERTIES)
+ set(_MY_PARAMS_PROPERTIES ${PROPERTYCOPY_DEFAULT_PROPERTY_LIST})
+ endif()
+
+ foreach(_prop IN LISTS _MY_PARAMS_PROPERTIES )
+ get_property(_set TARGET ${_MY_PARAMS_TGT} PROPERTY ${_prop} SET)
+ if (_set)
+ get_property(${_MY_PARAMS_PREFIX}_${_prop} TARGET ${_MY_PARAMS_TGT} PROPERTY ${_prop})
+ set(${_MY_PARAMS_PREFIX}_${_prop} ${${_MY_PARAMS_PREFIX}_${_prop}} PARENT_SCOPE)
+ endif()
+ endforeach()
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: translate_interface_target_properties
+
+ .. code-block:: cmake
+
+ # To translate default set of properties saved to variables with ``LIBC_`` prefix
+ # using :command:`save_interface_target_properties`. Result string returned to
+ # ``_cmake_fragment``
+ translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+
+ # To translate default set of properties saved to variables with ``LIBC_`` prefix
+ # using :command:`save_interface_target_properties`. Results saved to lists prefixed
+ # with ``LIBC_``. List of generated lists is returned in ``_lists``
+ translate_interface_target_properties(PREFIX LIBC RES _lists)
+
+ Construct a string of cmake script fragment setting global cmake variables configuring
+ build properties to match saved target interface settings. The script fragment is returned
+ in ``RES``
+ Intended usage is to help transferring target specific settings to sub projects using
+ initial cache files.
+ Warning: quotation in property values is not handled. This can cause problems e.g. with
+ computed includes.
+
+ If ``TO_LIST`` is passed translation will be done to a lists. ``RES`` will hold a list of
+ list names where the settings are saved.
+ This mode allows further processing on the lists, e.g. to be converted to ``CFLAGS`` or
+ ``LDFLAGS`` environment variables.
+
+ Works in tandem with :command:`save_interface_target_properties`.
+
+ Inputs:
+ ``PREFIX``
+ Target to set properties on.
+ ``VARS``
+ Name of variables to copy from.
+ ``TO_LIST``
+ Translate to lists instead of cmake script fragment.
+ Outputs
+ ``RES``
+ Name of variable to store the results to.
+#]===]
+function(translate_interface_target_properties)
+ set(_OPTIONS_ARGS TO_LIST)
+ set(_ONE_VALUE_ARGS PREFIX RES)
+ set(_MULTI_VALUE_ARGS VARS)
+ cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+ if (NOT DEFINED _MY_PARAMS_PREFIX)
+ message(FATAL_ERROR "Mandatory parameter PREFIX is not defined.")
+ endif()
+ string(LENGTH "${_MY_PARAMS_PREFIX}_" _PREFIX_LENGT)
+
+ if (NOT DEFINED _MY_PARAMS_RES)
+ message(FATAL_ERROR "Mandatory parameter RES is not defined.")
+ endif()
+
+ if (DEFINED _MY_PARAMS_VARS)
+ foreach(_VAR_NAME IN LISTS _MY_PARAMS_VARS)
+ if (NOT DEFINED ${_VAR_NAME})
+ message(FATAL_ERROR "Attempt to translate undefined variable \"${_VAR_NAME}\"")
+ endif()
+
+ string(SUBSTRING "${_VAR_NAME}" ${_PREFIX_LENGT} -1 _prop)
+ _prc_translate(PROP "${_prop}" VALUE ${${_VAR_NAME}} RES _res)
+
+ if(NOT "${_res}" STREQUAL "")
+ list(GET _res 0 _global_var_name)
+ list(GET _res 1 _global_var_value)
+ list(APPEND ${_MY_PARAMS_PREFIX}_${_global_var_name} ${_global_var_value})
+ if (NOT "${_MY_PARAMS_PREFIX}_${_global_var_name}" IN_LIST _RES)
+ list(APPEND _RES "${_MY_PARAMS_PREFIX}_${_global_var_name}")
+ endif()
+ endif()
+ endforeach()
+ else()
+ foreach(_prop IN LISTS PROPERTYCOPY_DEFAULT_PROPERTY_LIST)
+ set(_VAR_NAME "${_MY_PARAMS_PREFIX}_${_prop}")
+ # Is the variable holding the value of the property available?
+ if (DEFINED ${_VAR_NAME})
+ _prc_translate(PROP "${_prop}" VALUE ${${_VAR_NAME}} RES _res)
+ if(NOT "${_res}" STREQUAL "")
+ list(GET _res 0 _global_var_name)
+ list(GET _res 1 _global_var_value)
+ list(APPEND ${_MY_PARAMS_PREFIX}_${_global_var_name} ${_global_var_value})
+ if (NOT "${_MY_PARAMS_PREFIX}_${_global_var_name}" IN_LIST _RES)
+ list(APPEND _RES "${_MY_PARAMS_PREFIX}_${_global_var_name}")
+ endif()
+ endif()
+ endif()
+ endforeach()
+ endif()
+
+ if (_MY_PARAMS_TO_LIST)
+ foreach(_list_name IN LISTS _RES)
+ set(${_list_name} ${${_list_name}} PARENT_SCOPE)
+ endforeach()
+ set(${_MY_PARAMS_RES} ${_RES} PARENT_SCOPE)
+ else()
+ foreach(_list_name IN LISTS _RES)
+ string(SUBSTRING "${_list_name}" ${_PREFIX_LENGT} -1 _short_name)
+ string(REPLACE ";" " " _list_value "${${_list_name}}")
+ string(APPEND _STRING_RES "set(${_short_name} \"\${${_short_name}} ${_list_value}\" CACHE STRING \"\" FORCE)\n")
+ endforeach()
+ set(${_MY_PARAMS_RES} ${_STRING_RES} PARENT_SCOPE)
+ endif()
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: translate_value_as_property
+
+ .. code-block:: cmake
+
+ translate_value_as_property(VALUE "/foo/bar/include;/foo/bar/include1"
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ RES _cmake_fragment)
+
+ Translate a value as the specified property would be. Can be used to translate variables not saved
+ with :command:`save_interface_target_properties`
+
+ Inputs:
+ ``VALUE``
+ Value to be converted.
+ ``PROPERTY``
+ The interface property to set conversion type.
+ Outputs:
+ ``RES``
+ Name of variable to write result string to.
+#]===]
+function(translate_value_as_property)
+ set(_OPTIONS_ARGS)
+ set(_ONE_VALUE_ARGS VALUE PROPERTY RES)
+ set(_MULTI_VALUE_ARGS)
+ cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+ if (NOT DEFINED _MY_PARAMS_VALUE)
+ message(FATAL_ERROR "Mandatory parameter VALUE is not defined.")
+ endif()
+ if (NOT DEFINED _MY_PARAMS_RES)
+ message(FATAL_ERROR "Mandatory parameter RES is not defined.")
+ endif()
+ if (NOT DEFINED _MY_PARAMS_PROPERTY)
+ message(FATAL_ERROR "Mandatory parameter PROPERTY is not defined.")
+ endif()
+
+ set(A_${_MY_PARAMS_PROPERTY} ${_MY_PARAMS_VALUE})
+ translate_interface_target_properties(PREFIX A RES _cmake_fragment
+ VARS A_${_MY_PARAMS_PROPERTY})
+ set(${_MY_PARAMS_RES} ${_cmake_fragment} PARENT_SCOPE)
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: unset_saved_properties
+
+ .. code-block:: cmake
+
+ unset_saved_properties("LIBC")
+
+ Unset saved properties. For cleaning up the variable name space.
+
+ Inputs:
+ ``PREFIX``
+ Prefix to use for output variable names.
+#]===]
+macro(unset_saved_properties PREFIX)
+ foreach(_prc_prop IN LISTS PROPERTYCOPY_DEFAULT_PROPERTY_LIST )
+ set(_PRC_VAR_NAME ${PREFIX}_${_prc_prop})
+ unset(${_PRC_VAR_NAME})
+ endforeach()
+ unset(_PRC_VAR_NAME)
+ unset(_prc_prop)
+endmacro()
+
+#[===[.rst:
+.. cmake:command:: unset_translated_lists
+
+ .. code-block:: cmake
+
+ unset_translated_lists(_lists)
+
+ Unset saved properties. Can be used for cleaning up the variable name space.
+
+ Inputs:
+ ``LISTVAR``
+ Prefix to use for output variable names.
+#]===]
+macro(unset_translated_lists LISTVAR)
+ foreach(_list_name IN LISTS ${LISTVAR} )
+ unset(${_list_name})
+ endforeach()
+ unset(_list_name)
+endmacro()
+#[===[.rst:
+.. cmake:command:: print_saved_properties
+
+ .. code-block:: cmake
+
+ print_saved_properties(PREFIX LIBC)
+
+ Print the value of all target interface properties saved with the specified prefix.
+ Can be used for debugging.
+
+ Inputs:
+ ``PREFIX``
+ Prefix to use for output variable names.
+#]===]
+function(print_saved_properties)
+ set(_OPTIONS_ARGS)
+ set(_ONE_VALUE_ARGS PREFIX)
+ set(_MULTI_VALUE_ARGS )
+ cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+ if (NOT DEFINED _MY_PARAMS_PREFIX)
+ message(FATAL_ERROR "Mandatory parameter PREFIX is not defined.")
+ endif()
+ string(LENGTH "${_MY_PARAMS_PREFIX}_" _PREFIX_LENGT)
+
+ message(STATUS "Properties saved with prefix \"${_MY_PARAMS_PREFIX}\"")
+ foreach(_prop IN LISTS PROPERTYCOPY_DEFAULT_PROPERTY_LIST )
+ set(_VAR_NAME "${_MY_PARAMS_PREFIX}_${_prop}")
+ string(SUBSTRING "${_VAR_NAME}" ${_PREFIX_LENGT} -1 _prop)
+ if (NOT DEFINED ${_VAR_NAME})
+ set(_value "<Not set.>")
+ else()
+ set(_value ${${_VAR_NAME}})
+ endif()
+ message(STATUS " ${_prop}:${_value}")
+ endforeach()
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: print_translated_lists
+
+ .. code-block:: cmake
+
+ print_translated_lists(PREFIX LIBC)
+
+ Print the value of all lists translated from interface properties by calling
+ translate_interface_target_properties() with TO_LISTS set.
+ Can be used for debugging.
+
+ Inputs:
+ ``LIST``
+ Name of list of lists set by :command:`translate_interface_target_properties`
+#]===]
+function(print_translated_lists)
+ set(_OPTIONS_ARGS)
+ set(_ONE_VALUE_ARGS LIST)
+ set(_MULTI_VALUE_ARGS )
+ cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+ if (NOT DEFINED _MY_PARAMS_LIST)
+ message(FATAL_ERROR "Mandatory parameter LIST is not defined.")
+ endif()
+
+ message(STATUS "Translated lists from \"${_MY_PARAMS_LIST}\"")
+ foreach(_list IN LISTS ${_MY_PARAMS_LIST})
+ message(STATUS " ${_list}=${${_list}}")
+ endforeach()
+endfunction()
+
+# These properties are cmake specific and can not be translated.
+# INTERFACE_COMPILE_FEATURES, INTERFACE_LINK_DEPENDS, INTERFACE_SOURCES
+# LINK_INTERFACE_LIBRARIES
+
+# Translate target property to command line switch.
+function(_prc_translate)
+ set(_OPTIONS_ARGS)
+ set(_ONE_VALUE_ARGS PROP RES)
+ set(_MULTI_VALUE_ARGS VALUE)
+ cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+ if ("${_MY_PARAMS_VALUE}" STREQUAL "")
+ set(_res "")
+ else()
+ if (_MY_PARAMS_PROP STREQUAL INTERFACE_INCLUDE_DIRECTORIES)
+ _prc_translate_include_list("${_MY_PARAMS_VALUE}" _res)
+ elseif(_MY_PARAMS_PROP STREQUAL INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
+ _prc_translate_system_include_list("${_MY_PARAMS_VALUE}" _res)
+ elseif(_MY_PARAMS_PROP STREQUAL INTERFACE_COMPILE_DEFINITIONS)
+ _prc_translate_macro_list("${_MY_PARAMS_VALUE}" _res)
+ elseif(_MY_PARAMS_PROP STREQUAL INTERFACE_COMPILE_OPTIONS)
+ _prc_translate_compile_option_list("${_MY_PARAMS_VALUE}" _res)
+ elseif(_MY_PARAMS_PROP STREQUAL INTERFACE_LINK_OPTIONS)
+ _prc_translate_link_option_list("${_MY_PARAMS_VALUE}" _res)
+ elseif(_MY_PARAMS_PROP STREQUAL INTERFACE_LINK_DIRECTORIES)
+ _prc_translate_link_directory_list("${_MY_PARAMS_VALUE}" _res)
+ elseif(_MY_PARAMS_PROP STREQUAL INTERFACE_LINK_LIBRARIES)
+ _prc_translate_link_library_list("${_MY_PARAMS_VALUE}" _res)
+ else()
+ message(FATAL_ERROR "Can not translate target property \"${_MY_PARAMS_PROP}\" to global setting.")
+ endif()
+ endif()
+ set(${_MY_PARAMS_RES} "${_res}" PARENT_SCOPE)
+endfunction()
+
+# Translate list of include directories to compiler flags.
+function(_prc_translate_include_list VALUE OUT)
+ if(NOT "${VALUE}" STREQUAL "")
+ string(REPLACE ";" " ${CMAKE_INCLUDE_FLAG_C} " _tmp "${VALUE}")
+ else()
+ set(_tmp "")
+ endif()
+ set(${OUT} "CMAKE_C_FLAGS_INIT;${CMAKE_INCLUDE_FLAG_C} ${_tmp}" PARENT_SCOPE)
+endfunction()
+
+# Translate list of system include directories to compiler flags.
+function(_prc_translate_system_include_list VALUE OUT)
+ if(NOT "${VALUE}" STREQUAL "")
+ string(REPLACE ";" " ${CMAKE_INCLUDE_SYSTEM_FLAG_C} " _tmp "${VALUE}")
+ else()
+ set(_tmp "")
+ endif()
+ set(${OUT} "CMAKE_C_FLAGS_INIT;${CMAKE_INCLUDE_SYSTEM_FLAG_C} ${_tmp}" PARENT_SCOPE)
+endfunction()
+
+# Translate list of C macro definitions to compiler flags.
+function(_prc_translate_macro_list VALUE OUT)
+ if(NOT "${VALUE}" STREQUAL "")
+ string(REPLACE ";" " -D " _tmp "${VALUE}")
+ else()
+ set(_tmp "")
+ endif()
+ set(${OUT} "CMAKE_C_FLAGS_INIT;-D ${_tmp}" PARENT_SCOPE)
+endfunction()
+
+# Translate list of compilation options to compiler flags.
+function(_prc_translate_compile_option_list VALUE OUT)
+ if(NOT "${VALUE}" STREQUAL "")
+ string(REPLACE ";" " " _tmp "${VALUE}")
+ else()
+ set(_tmp "")
+ endif()
+ set(${OUT} "CMAKE_C_FLAGS_INIT;${_tmp}" PARENT_SCOPE)
+endfunction()
+
+# Translate list of link options to linker flags.
+function(_prc_translate_link_option_list VALUE OUT)
+ if(NOT "${VALUE}" STREQUAL "")
+ string(REPLACE ";" " " _tmp "${VALUE}")
+ else()
+ set(_tmp "")
+ endif()
+ set(${OUT} "CMAKE_EXE_LINKER_FLAGS_INIT;${_tmp}" PARENT_SCOPE)
+endfunction()
+
+# Translate list of linker search paths to linker flags.
+function(_prc_translate_link_directory_list VALUE OUT)
+ if(NOT "${VALUE}" STREQUAL "")
+ string(REPLACE ";" " ${CMAKE_LIBRARY_PATH_FLAG} " _tmp "${VALUE}")
+ else()
+ set(_tmp "")
+ endif()
+ set(${OUT} "CMAKE_EXE_LINKER_FLAGS_INIT;${CMAKE_LIBRARY_PATH_FLAG} ${_tmp}" PARENT_SCOPE)
+endfunction()
+
+# Translate list of libraries to linker flags.
+function(_prc_translate_link_library_list VALUE OUT)
+ if(NOT "${VALUE}" STREQUAL "")
+ string(REPLACE ";" " ${CMAKE_LINK_LIBRARY_FLAG} " _tmp "${VALUE}")
+ else()
+ set(_tmp "")
+ endif()
+ set(${OUT} "CMAKE_EXE_LINKER_FLAGS_INIT;${CMAKE_LINK_LIBRARY_FLAG} ${_tmp}" PARENT_SCOPE)
+endfunction()
diff --git a/tools/cmake/common/TargetCompileDefinitions.cmake b/tools/cmake/common/TargetCompileDefinitions.cmake
new file mode 100644
index 000000000..069c38207
--- /dev/null
+++ b/tools/cmake/common/TargetCompileDefinitions.cmake
@@ -0,0 +1,65 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+include(${CMAKE_CURRENT_LIST_DIR}/Uuid.cmake)
+
+#[===[.rst:
+.. cmake:command:: set_target_uuids
+
+.. code:: cmake
+
+set_target_uuids(
+ SP_UUID <uuid>
+ SP_NAME <name>
+ )
+
+INPUTS:
+
+``SP_UUID``
+The UUID of the SP as a string.
+
+``SP_NAME``
+The name of the SP.
+
+#]===]
+
+function (set_target_uuids)
+ set(options)
+ set(oneValueArgs TGT SP_UUID)
+ set(multiValueArgs)
+ cmake_parse_arguments(_MY_PARAMS "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN} )
+
+ check_args(SP_UUID TGT)
+
+ # Convert the UUID to a C char array initializer e.g.
+ # { 0x01, 0x10, 0x9c, 0xf8, 0xe5, 0xca, 0x44, 0x6f,
+ # 0x9b, 0x55, 0xf3, 0xcd, 0xc6, 0x51, 0x10, 0xc8, }
+ # and "pass it" to C files.
+ uuid_canon_to_octets(UUID ${_MY_PARAMS_SP_UUID} RES UUID_OCTETS)
+ list(JOIN UUID_OCTETS ", 0x" UUID_BYTES )
+ set(UUID_BYTES "{ 0x${UUID_BYTES} }")
+ target_compile_definitions(${_MY_PARAMS_TGT}
+ PRIVATE OPTEE_SP_UUID_BYTES=${UUID_BYTES}
+ )
+
+ # Create a UUID structure with the UUID fileds
+ # { 0x01109cf8, 0xe5ca, 0x446f, \
+ # { 0x9b, 0x55, 0xf3, 0xcd, 0xc6, 0x51, 0x10, 0xc8 } }
+ # and "pass it" to C files
+ uuid_canon_to_fields(UUID ${_MY_PARAMS_SP_UUID}
+ TIME_LOW "_uuid_timeLow"
+ TIME_MID "_uuid_timeMid"
+ TIME_HI_AND_VER "_uuid_timeHiAndVersion"
+ CLOCK_AND_SEQ "_uuid_clockSeqAndNode")
+ string(REGEX MATCHALL ".." _uuid_clockSeqAndNode "${_uuid_clockSeqAndNode}")
+ list(JOIN _uuid_clockSeqAndNode ", 0x" _uuid_clockSeqAndNode)
+ set(UUID_STRUCT "{ 0x${_uuid_timeLow}, 0x${_uuid_timeMid}, 0x${_uuid_timeHiAndVersion}, { 0x${_uuid_clockSeqAndNode} }}")
+ target_compile_definitions(${_MY_PARAMS_TGT}
+ PRIVATE OPTEE_SP_UUID=${UUID_STRUCT}
+ )
+endfunction()
diff --git a/tools/cmake/common/Utils.cmake b/tools/cmake/common/Utils.cmake
index c889320bf..256bbf928 100644
--- a/tools/cmake/common/Utils.cmake
+++ b/tools/cmake/common/Utils.cmake
@@ -49,3 +49,60 @@ function(ts_verify_build_env)
endif()
endif()
endFunction()
+
+#[===[.rst:
+.. cmake:command:: ts_add_uuid_to_exe_name
+
+ .. code-block:: cmake
+
+ ts_add_uuid_to_exe_name(TGT <target name> UUID "canonical string")
+
+ A function to modify the file name of the binary produced by a deployment to allow the OP-TEE symbolize.py tool to
+ find it when analyzing stack dumps. This is only useful for SP deployments targeting OP-TEE.
+ The filename will follow the template <file name>_<UUID>.elf format, where
+ - file name is the original name already configured for the target
+ - UUID is an argument of this function
+
+ INPUTS:
+
+ ``TGT``
+ Mandatory. The name of the target to manipulate.
+
+ ``UUID``
+ Mandatory. The UUID to be used to identify the SP. This has to match the UUID used by OP-TEE OS to identify the SP
+ runtime.
+
+#]===]
+function(ts_add_uuid_to_exe_name)
+ set(options)
+ set(oneValueArgs TGT UUID)
+ set(multiValueArgs)
+ cmake_parse_arguments(_MY_PARAMS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ check_args(ts_add_uuid_to_exe_name TGT)
+
+ get_target_property(_tgt_type ${_MY_PARAMS_TGT} TYPE)
+ if ("${_tgt_type}" STREQUAL "EXECUTABLE")
+ check_args(ts_add_uuid_to_exe_name UUID)
+ get_target_property(_out_name ${_MY_PARAMS_TGT} OUTPUT_NAME)
+ if (NOT _out_name)
+ set(_out_name "${_MY_PARAMS_TGT}")
+ endif()
+ get_target_property(_suffix ${_MY_PARAMS_TGT} SUFFIX)
+ if (NOT _suffix)
+ # Note CMAKE_EXECUTABLE_SUFFIX_<lang> might be needed here. Unfortunately
+ # this is only set, when it is set manually. It overrides the EXE_SUFFIX
+ # when set.
+ set(_suffix ${CMAKE_EXECUTABLE_SUFFIX})
+ endif()
+ # If executable suffix is still not set at this point, use the full name as basename.
+ if (_suffix)
+ string(REGEX REPLACE "${_suffix}$" "" _base_name "${_out_name}")
+ else()
+ set(_base_name "${_out_name}")
+ endif()
+
+ set(_out_name "${_base_name}_${_MY_PARAMS_UUID}${_suffix}")
+ set_target_properties(${_MY_PARAMS_TGT} PROPERTIES OUTPUT_NAME "${_out_name}")
+ endif()
+endfunction()
diff --git a/tools/cmake/common/Uuid.cmake b/tools/cmake/common/Uuid.cmake
new file mode 100644
index 000000000..d66a7a3e9
--- /dev/null
+++ b/tools/cmake/common/Uuid.cmake
@@ -0,0 +1,166 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+include_guard()
+
+#[===[.rst:
+RFC 4122 compatible UUID manipulation routines
+---------------------------------------------
+
+The functionality in this file allows manipulating (which mostly means conversion) of UUID strings
+to various formats used in the TS build system.
+
+#]===]
+
+#[===[.rst:
+.. cmake:command:: uuid_canon_to_octets
+
+ .. code-block:: cmake
+
+ uuid_canon_to_octets(UUID <canonical UUID string> RES <output variable name>)
+
+ Convert a canonical UUID string to list of bytes, where each byte is represented as a two digit
+ hex octet without any prefix of suffix. Order of bytes will match the order of octets in the
+ canonical string left to right.
+
+ INPUTS:
+
+ ``UUID``
+ Canonical UUID string.
+
+ OUTPUTS:
+
+ ``RES``
+ Name of variable to store the result to. The result is a list of strings, where each list item
+ is a two digit hex digit, without any prefix or suffix.
+
+#]===]
+function(uuid_canon_to_octets)
+ set(options)
+ set(oneValueArgs UUID RES)
+ set(multiValueArgs)
+ cmake_parse_arguments(_MY_PARAMS "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN} )
+
+ check_args(UUID RES)
+
+ string(REGEX MATCHALL "([A-Za-z0-9][A-Za-z0-9])" _hex_bytes "${_MY_PARAMS_UUID}")
+ list(LENGTH _hex_bytes _len)
+ if(NOT _len EQUAL 16)
+ message(FATAL_ERROR "Failed to convert UUID \"${_MY_PARAMS_UUID}\" to bytes. Failed to get exactly 16 octets.")
+ endif()
+ set(${_MY_PARAMS_RES} ${_hex_bytes} PARENT_SCOPE)
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: uuid_canon_to_fields
+
+ .. code-block:: cmake
+
+ uuid_canon_to_fields(UUID <canonical UUIdD string> TIME_LOW <output variable name> TIME_MID <output variable name>
+ TIME_HI_AND_VER <output variable name> CLOCK_AND_SEQ <output variable name>)
+
+ Convert a canonical UUID string to UUID fields. Each field is a
+
+ INPUTS:
+
+ ``UUID``
+ Canonical UUID string.
+
+ OUTPUTS:
+ ``TIME_LOW``
+ Name of variable to store the time low filed.
+
+ ``TIME_MID``
+ Name of variable to store the time mid filed.
+
+ ``TIME_HI_AND_VER``
+ Name of variable to store the time hi and version filed.
+
+ ``CLOCK_AND_SEQ``
+ Name of variable to store the clock and sequence filed.
+
+#]===]
+function(uuid_canon_to_fields)
+ set(options)
+ set(oneValueArgs UUID TIME_LOW TIME_MID TIME_HI_AND_VER CLOCK_AND_SEQ)
+ set(multiValueArgs)
+ cmake_parse_arguments(_MY_PARAMS "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN} )
+
+ check_args(UUID TIME_LOW TIME_MID TIME_HI_AND_VER CLOCK_AND_SEQ)
+ uuid_canon_to_octets(UUID ${_MY_PARAMS_UUID} RES _uuid_octets)
+
+ #Split the list of bytes in to the struct fields
+ list(SUBLIST _uuid_octets 0 4 _uuid_timeLow)
+ list(JOIN _uuid_timeLow "" _uuid_timeLow)
+
+ list(SUBLIST _uuid_octets 4 2 _uuid_timeMid)
+ list(JOIN _uuid_timeMid "" _uuid_timeMid)
+
+ list(SUBLIST _uuid_octets 6 2 _uuid_timeHiAndVersion)
+ list(JOIN _uuid_timeHiAndVersion "" _uuid_timeHiAndVersion)
+
+ list(SUBLIST _uuid_octets 8 8 _uuid_clockSeqAndNode)
+ list(JOIN _uuid_clockSeqAndNode "" _uuid_clockSeqAndNode)
+
+ set(${_MY_PARAMS_TIME_LOW} ${_uuid_timeLow} PARENT_SCOPE)
+ set(${_MY_PARAMS_TIME_MID} ${_uuid_timeMid} PARENT_SCOPE)
+ set(${_MY_PARAMS_TIME_HI_AND_VER} ${_uuid_timeHiAndVersion} PARENT_SCOPE)
+ set(${_MY_PARAMS_CLOCK_AND_SEQ} ${_uuid_clockSeqAndNode} PARENT_SCOPE)
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: uuid_canon_to_le_words
+
+ .. code-block:: cmake
+
+ uuid_canon_to_le_words(UUID <canonical UUID string> RES <output variable name>)
+
+ Convert a canonical UUID string to list of 32bit wide little-endian numbers represented
+ as hex strings.
+
+ INPUTS:
+
+ ``UUID``
+ Canonical UUID string.
+
+ ``RES``
+ Name of variable to store the result to.
+
+#]===]
+function(uuid_canon_to_le_words)
+ set(options)
+ set(oneValueArgs UUID RES)
+ set(multiValueArgs)
+ cmake_parse_arguments(_MY_PARAMS "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN} )
+
+ check_args(UUID RES)
+ uuid_canon_to_octets(UUID ${_MY_PARAMS_UUID} RES _uuid_octets)
+
+ # Separate 32 bit chunks
+ list(SUBLIST _uuid_octets 0 4 _word1)
+ list(SUBLIST _uuid_octets 4 4 _word2)
+ list(SUBLIST _uuid_octets 8 4 _word3)
+ list(SUBLIST _uuid_octets 12 4 _word4)
+
+ # Reverse octet order each word
+ list(REVERSE _word1)
+ list(REVERSE _word2)
+ list(REVERSE _word3)
+ list(REVERSE _word4)
+
+ # Concatenate octets of each word to a single string
+ list(JOIN _word1 "" _word1)
+ list(JOIN _word2 "" _word2)
+ list(JOIN _word3 "" _word3)
+ list(JOIN _word4 "" _word4)
+
+ # Return the result
+ set(${_MY_PARAMS_RES} "${_word1}" "${_word2}" "${_word3}" "${_word4}" PARENT_SCOPE)
+endfunction()
diff --git a/tools/cmake/compiler/GCC.cmake b/tools/cmake/compiler/GCC.cmake
index fcb40afad..79f915821 100644
--- a/tools/cmake/compiler/GCC.cmake
+++ b/tools/cmake/compiler/GCC.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2019-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2019-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -16,15 +16,29 @@ Compiler abstraction for GCC
The variable can be set on the command line with ``-DCROSS_COMPILE=<value>`` or in the
environment. If both is specified, command line takes precedence.
-#]===]
+.. cmake:variable:: LIBGCC_PATH
-include_guard(DIRECTORY)
+ An absolute path to specify the location of the gcc specific library. The name
+ of the library is libgcc.a. Note that it must be the full path with library name.
+ The variable can be set on the command line with ``-DLIBGCC_PATH=<value>`` or in the
+ environment. If both is specified, command line takes precedence.
-if(NOT CROSS_COMPILE AND NOT DEFINED ENV{CROSS_COMPILE})
- message(FATAL_ERROR "'CROSS_COMPILE' is not defined. Set it to the gcc pferix triplet, ie. cmake <..>-DCROSS_COMPILE=aarch64-elf-")
-endif()
+.. cmake:variable:: LIBGCC_INCLUDE_DIRS
+
+ A semicolon separated list of absolute paths to specify the location of gcc specific header
+ files. The variable can be set on the command line with ``-DLIBGCC_INCLUDE_DIRS=<value>``
+ or in the environment. If both is specified, command line takes precedence.
-set(CROSS_COMPILE $ENV{CROSS_COMPILE} CACHE STRING "Prefix of the cross-compiler commands")
+.. cmake:variable:: LIBGCC_LOCATE_CFLAGS
+
+ The compiler options used when searching for the gcc library (libgcc.a).
+ Setting the value is optional.
+ The variable can be set on the command line with ``-DLIBGCC_LOCATE_CFLAGS=<value>`` or
+ in the environment.
+
+#]===]
+
+include_guard(DIRECTORY)
#Generate a list of tool names to look for. Store the result in CMAKE_<lang>_COMPILER.
function(gcc_find_tool NAME LANG)
@@ -37,13 +51,21 @@ function(gcc_find_tool NAME LANG)
set(CMAKE_${LANG}_COMPILER ${_cross_compile_gcc} CACHE STRING "${LANG} compiler executable.")
endfunction()
-gcc_find_tool(gcc C)
-gcc_find_tool(g++ CXX)
+if(CMAKE_CROSSCOMPILING)
+ if(NOT CROSS_COMPILE AND NOT DEFINED ENV{CROSS_COMPILE})
+ message(FATAL_ERROR "'CROSS_COMPILE' is not defined. Set it to the gcc prefix triplet, ie. cmake <..>-DCROSS_COMPILE=aarch64-elf-")
+ endif()
+
+ set(CROSS_COMPILE $ENV{CROSS_COMPILE} CACHE STRING "Prefix of the cross-compiler commands")
-#Official solution to disable compiler checks
-set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+ gcc_find_tool(gcc C)
+ gcc_find_tool(g++ CXX)
-#By default when INTERFACE_INCUDES of libraryes linked to an exe are treated
+ #Official solution to disable compiler checks
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+endif()
+
+#By default when INTERFACE_INCUDES of libraries linked to an exe are treated
#as system includes. gcc-arm-8.2-2019.01-i686-mingw32-aarch64-elf (gcc 8.2.1) will
#set C linkage o these files, which will result in compilation errors for C++ projects.
#This setting fixes that.
@@ -54,9 +76,9 @@ set(CMAKE_NO_SYSTEM_FROM_IMPORTED True)
.. code-block:: cmake
- compiler_preprocess_file(SRC file.c DST file_pp.c)
- compiler_preprocess_file(SRC file.c DST file_pp.c
- DEFINES USE_LIB INCLUDES include/lib)
+ compiler_preprocess_file(SRC file.c DST file_pp.c)
+ compiler_preprocess_file(SRC file.c DST file_pp.c
+ DEFINES USE_LIB INCLUDES include/lib)
Run the preprocessor on a file and save the output to another file. Optionally
provide defines and include paths to the preprocessor.
@@ -64,21 +86,24 @@ set(CMAKE_NO_SYSTEM_FROM_IMPORTED True)
Inputs:
``SRC``
- Name of the source file to preprocess.
+ Name of the source file to preprocess.
``DST``
- Where to write the preprocessed output.
+ Where to write the preprocessed output.
+
+ ``TARGET`` (optional)
+ Target that the custom command is tied to.
``DEFINES`` (multi, optional)
- Definitions for the preprocessor.
+ Definitions for the preprocessor.
``INCLUDES`` (multi, optional)
- Include paths for the preprocessor.
+ Include paths for the preprocessor.
#]===]
function(compiler_preprocess_file)
set(_OPTIONS_ARGS)
- set(_ONE_VALUE_ARGS SRC DST)
+ set(_ONE_VALUE_ARGS TARGET SRC DST)
set(_MULTI_VALUE_ARGS DEFINES INCLUDES)
cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
@@ -94,11 +119,22 @@ function(compiler_preprocess_file)
list(APPEND _flags ${_MY_PARAMS_INCLUDES})
endif()
- add_custom_command(
- DEPENDS ${_MY_PARAMS_SRC} OUTPUT ${_MY_PARAMS_DST}
- COMMAND ${CMAKE_C_COMPILER} -E -P -x assembler-with-cpp ${_flags}
- ${_MY_PARAMS_SRC} -o ${_MY_PARAMS_DST}
- )
+ if(_MY_PARAMS_TARGET)
+ add_custom_command(
+ TARGET ${_MY_PARAMS_TARGET}
+ POST_BUILD
+ DEPENDS ${_MY_PARAMS_SRC}
+ COMMAND ${CMAKE_C_COMPILER} -E -P -x assembler-with-cpp ${_flags}
+ ${_MY_PARAMS_SRC} -o ${_MY_PARAMS_DST}
+ )
+ else()
+ add_custom_command(
+ DEPENDS ${_MY_PARAMS_SRC}
+ OUTPUT ${_MY_PARAMS_DST}
+ COMMAND ${CMAKE_C_COMPILER} -E -P -x assembler-with-cpp ${_flags}
+ ${_MY_PARAMS_SRC} -o ${_MY_PARAMS_DST}
+ )
+ endif()
endfunction()
#[===[.rst:
@@ -106,8 +142,8 @@ endfunction()
.. code-block:: cmake
- compiler_set_linker_script(TARGET foo FILE foo.ld.S)
- compiler_set_linker_script(TARGET foo FILE foo.ld.S DEF USE_LIB INC include/lib)
+ compiler_set_linker_script(TARGET foo FILE foo.ld.S)
+ compiler_set_linker_script(TARGET foo FILE foo.ld.S DEF USE_LIB INC include/lib)
Set linker script for a target. The function adds an LDFLAG using the
toolchain specific syntax to the TARGET_linker_script group, which is applied
@@ -117,16 +153,16 @@ endfunction()
Inputs:
``TARGET``
- Name of the target.
+ Name of the target.
``FILE``
- Linker script file for the target.
+ Linker script file for the target.
``DEF`` (multi, optional)
- Defines for the linker script preprocessor.
+ Defines for the linker script preprocessor.
``INC`` (multi, optional)
- Include paths for the linker script preprocessor.
+ Include paths for the linker script preprocessor.
#]===]
function(compiler_set_linker_script)
@@ -164,7 +200,7 @@ endfunction()
.. code-block:: cmake
- compiler_generate_binary_output(TARGET <name> RES <var>)
+ compiler_generate_binary_output(TARGET <name> RES <var>)
Generate binary output for the target. The function converts the output
executable into bin file using toolchain specific syntax.
@@ -172,17 +208,17 @@ endfunction()
Inputs:
``TARGET``
- Name of the target.
+ Name of the target.
Outputs:
``RES``
- Full patch to output file.
+ Full patch to output file.
#]===]
function(compiler_generate_binary_output)
set(options)
- set(oneValueArgs TARGET)
+ set(oneValueArgs TARGET NAME RES)
set(multiValueArgs)
cmake_parse_arguments(MY "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
@@ -190,9 +226,9 @@ function(compiler_generate_binary_output)
TARGET ${MY_TARGET} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary
$<TARGET_FILE:${MY_TARGET}>
- $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_TARGET}.bin)
+ $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME})
if (MY_RES)
- set(${MY_RES} $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_TARGET}.bin PARENT_SCOPE)
+ set(${MY_RES} $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME} PARENT_SCOPE)
endif()
endfunction()
@@ -202,7 +238,7 @@ endfunction()
.. code-block:: cmake
- compiler_generate_stripped_elf(TARGET foo NAME foo.stripped.elf RES var)
+ compiler_generate_stripped_elf(TARGET foo NAME foo.stripped.elf RES var)
Strip all symbols that are not needed for relocation processing and return the location
of the result.
@@ -210,15 +246,15 @@ endfunction()
Inputs:
``TARGET``
- Name of the target.
+ Name of the target.
``NAME``
- Name of output file
+ Name of output file
Outputs:
``RES``
- Name of variable to store the full path of the stripped executable.
+ Name of variable to store the full path of the stripped executable.
#]===]
@@ -244,21 +280,23 @@ endfunction()
.. code-block:: cmake
- gcc_get_lib_location(TARGET foo NAME foo.stripped.elf RES var)
+ gcc_get_lib_location(TARGET foo NAME foo.stripped.elf RES var)
Query the location of a specific library part of the GCC binary release. Can
- be used to find built in libraryes like libgcc.a when i.w. -nostdlib option
+ be used to find built in libraries like libgcc.a when i.w. -nostdlib option
is used.
+ The function uses the :variable:`LIBGCC_LOCATE_CFLAGS`.
+
Inputs:
``LIBRARY_NAME``
- Name of the library to search for.
+ Name of the library to search for.
Outputs:
``RES``
- Name of variable to store the full path of the library.
+ Name of variable to store the full path of the library.
#]===]
function(gcc_get_lib_location)
@@ -267,17 +305,166 @@ function(gcc_get_lib_location)
set(multiValueArgs)
cmake_parse_arguments(MY "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
+
+ if (DEFINED ENV{LIBGCC_LOCATE_CFLAGS})
+ set(LIBGCC_LOCATE_CFLAGS $ENV{LIBGCC_LOCATE_CFLAGS} CACHE STRING "GCC library search options" )
+ endif()
+
execute_process(
- COMMAND ${CMAKE_C_COMPILER} "--print-file-name=${MY_LIBRARY_NAME}"
+ COMMAND ${CMAKE_C_COMPILER} ${LIBGCC_LOCATE_CFLAGS} "--print-file-name=${MY_LIBRARY_NAME}"
OUTPUT_VARIABLE _RES
RESULT_VARIABLE _GCC_ERROR_CODE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(_GCC_ERROR_CODE GREATER 0)
- message(WARNING "GCC (${CMAKE_C_COMPILER}) invocation failed, can not determine location of library ${MY_LIBRARY_NAME}.")
+ message(WARNING "GCC (${CMAKE_C_COMPILER}) invocation failed, cannot determine location of library \"${MY_LIBRARY_NAME}\".")
+ set(_RES "${LIBRARY_NAME}-NOTFOUND")
+ endif()
+
+ if (NOT IS_ABSOLUTE "${_RES}")
+ message(WARNING "GCC (${CMAKE_C_COMPILER}) failed to return the location of file \"${MY_LIBRARY_NAME}\".")
set(_RES "${LIBRARY_NAME}-NOTFOUND")
endif()
set(${MY_RES} ${_RES} PARENT_SCOPE)
endfunction()
+
+
+#[===[.rst:
+.. cmake:command:: compiler_set_freestanding
+
+ .. code-block:: cmake
+
+ compiler_set_freestanding(TARGET foo)
+
+ Configure the target specified for "freestanging" compilation mode. Please see [1] for more information.
+ This will configure the target:
+ - to block access to the "built in" standard library and its headers
+ - link compiler specific libraries
+ - add include paths to compiler specific headers
+
+ All settings will be PUBLIC or INTERFACE (for imported targets) and thus will take effect on targets
+ depending on the configured one.
+
+ The function uses and manipulates the following CACHE variables:
+ - :variable:`LIBGCC_PATH`
+ - :variable:`LIBGCC_INCLUDE_DIRS`
+
+ CMake has a spacial behavior which needs a workaround. CMake is automatically filtering out built in compiler
+ include paths from the compiler command line.
+ As a workaround, compiler specific headers are copied to the build directory and set include path to the new
+ location.
+
+ Limitations:
+ - Inheritance of target settings may be problematic. Compiling components in "freestanding" mode may put
+ restrictions on reusing these. When such components are installed, the "freestanding" nature shall be
+ propagated to dependencies. This is not tested or implemented.
+
+ 1: https://wiki.osdev.org/Implications_of_writing_a_freestanding_C_project
+ 2: https://gitlab.kitware.com/cmake/cmake/-/issues/19227
+
+ Inputs:
+
+ ``TARGET``
+ Name of the target to configure.
+
+ Outputs:
+
+ N/A
+
+#]===]
+function(compiler_set_freestanding)
+ set(options)
+ set(oneValueArgs TARGET)
+ set(multiValueArgs)
+ cmake_parse_arguments(MY "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN} )
+
+ # Validate parameters
+ if (NOT DEFINED MY_TARGET)
+ message(FATAL_ERROR "Mandatory parameter TARGET is missing!")
+ endif()
+
+ # Set INTERFACE options for imported targets and PUBLIC otherwise.
+ get_property(_is_imported_target TARGET ${MY_TARGET} PROPERTY IMPORTED SET)
+ if (_is_imported_target)
+ set(_option_type INTERFACE)
+ else()
+ set(_option_type PUBLIC)
+ endif()
+
+ ### Get the location of libgcc.a
+ # Copy values from environment if present. Note: if the value is already in the CACHE, this set will have no effect.
+ if(DEFINED ENV{LIBGCC_PATH})
+ set(LIBGCC_PATH $ENV{LIBGCC_PATH} CACHE PATH "location of libgcc.a")
+ endif()
+ if (NOT DEFINED LIBGCC_PATH)
+ gcc_get_lib_location(LIBRARY_NAME "libgcc.a" RES _TMP_VAR)
+
+ if (NOT _TMP_VAR)
+ message(FATAL_ERROR "Location of libgcc.a can not be determined. Please set LIBGCC_PATH on the command"
+ " line or in the environment.")
+ endif()
+ set(LIBGCC_PATH ${_TMP_VAR} CACHE PATH "location of libgcc.a")
+ unset(_TMP_VAR)
+ endif()
+
+ # Validate LIBGCC_PATH
+ if(NOT EXISTS "${LIBGCC_PATH}" OR IS_DIRECTORY "${LIBGCC_PATH}")
+ message(FATAL_ERROR "LIBGCC_PATH \"${LIBGCC_PATH}\" must be the full path of a library file."
+ " Either set LIBGCC_PATH on the command line (or in the environment), or fix the existing"
+ " value.")
+ endif()
+ message(STATUS "libgcc.a for target \"${MY_TARGET}\" is used from ${LIBGCC_PATH}")
+
+ ### Get the location of libgcc specific header files.
+ # Copy values from environment if present. Note: if the value is already in the CACHE, this set will have no effect.
+ if(DEFINED ENV{LIBGCC_INCLUDE_DIRS})
+ set(LIBGCC_INCLUDE_DIRS $ENV{LIBGCC_INCLUDE_DIRS} CACHE STRING "GCC specific include PATHs")
+ endif()
+ if(NOT DEFINED LIBGCC_INCLUDE_DIRS)
+ # We can get the correct path if we ask for a location without a library name
+ gcc_get_lib_location(LIBRARY_NAME "" RES _TMP_VAR)
+
+ if (NOT _TMP_VAR)
+ message(FATAL_ERROR "Location of GCC specific include PATHs can not be determined. Please set"
+ " LIBGCC_INCLUDE_DIRS on the command line or in the environment.")
+ endif()
+
+ set(LIBGCC_INCLUDE_DIRS
+ "${_TMP_VAR}/include"
+ "${_TMP_VAR}/include-fixed" CACHE STRING "GCC specific include PATHs")
+ unset(_TMP_VAR)
+ endif()
+
+ # There is no way to stop cmake from filtering out built in compiler include paths
+ # from compiler command line (see https://gitlab.kitware.com/cmake/cmake/-/issues/19227).
+ # As a workaround copy headers to build directory and set include path to the new
+ # location.
+ # Also validate locations.
+ if (NOT GCC_INCLUDES_MOVED)
+ foreach(_dir IN LISTS LIBGCC_INCLUDE_DIRS)
+ if(NOT IS_DIRECTORY "${_dir}")
+ message(FATAL_ERROR "GCC specific include PATH \"${_dir}\" does not exist.")
+ endif()
+
+ file(COPY "${_dir}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gcc-include")
+ get_filename_component(_TMP_VAR "${_dir}" NAME)
+ list(APPEND _gcc_include_dirs "${CMAKE_CURRENT_BINARY_DIR}/gcc-include/${_TMP_VAR}")
+ message(STATUS "Compiler specific include path \"${_dir}\" mirrored to"
+ " \"${CMAKE_CURRENT_BINARY_DIR}/gcc-include/${_TMP_VAR}\".")
+ endforeach()
+ unset(_TMP_VAR)
+ set(GCC_INCLUDES_MOVED True CACHE BOOL "GCC include files are already copied.")
+ mark_as_advanced(GCC_INCLUDES_MOVED)
+ # Fix the variable in the CACHE.
+ set(LIBGCC_INCLUDE_DIRS ${_gcc_include_dirs} CACHE STRING "GCC specific include PATHs" FORCE)
+ endif()
+
+ # Configure the target for freestanding mode.
+ target_compile_options(${MY_TARGET} ${_option_type} "-nostdinc")
+ target_include_directories(${MY_TARGET} SYSTEM ${_option_type} ${LIBGCC_INCLUDE_DIRS})
+ target_link_options(${MY_TARGET} ${_option_type} "-nostdlib" "-nostartfiles")
+ target_link_libraries(${MY_TARGET} ${_option_type} "${LIBGCC_PATH}")
+endfunction()
diff --git a/tools/python/elf_segments_to_manifest.py b/tools/python/elf_segments_to_manifest.py
new file mode 100644
index 000000000..552816456
--- /dev/null
+++ b/tools/python/elf_segments_to_manifest.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+
+"""
+This module's goal is to take an ELF file as an input and extract the memory
+regions that need to be configured on load. The memory region description is put
+into the manifest file so the SPMC set up the memory layout when loading a
+binary format SP.
+"""
+
+from enum import IntFlag
+from math import ceil
+from elftools.elf.elffile import ELFFile
+from elftools.elf.constants import P_FLAGS
+
+
+class ElfSegmentsToManifest:
+ """
+ The class loads an ELF file and builds up an internal represention of its
+ memory layout then it can write this information into a manifest file.
+ """
+ PAGE_SIZE = 4096
+
+ class Region:
+ """ Describes a memory region and its attributes. """
+
+ class ManifestMemAttr(IntFlag):
+ """ Type for describing the memory flags of a region. """
+ R = 0x01
+ W = 0x02
+ X = 0x04
+
+ def get_attr(self):
+ """ Queries the value of the attributes in manifest format. """
+ return self.value
+
+ def __str__(self):
+ return ",".join([str(f.name) for f in __class__ if f in self])
+
+ @staticmethod
+ def from_p_flags(p_flags):
+ """ Creates an instanced initialized by p_flags. """
+ instance = 0
+ instance |= __class__.R if p_flags & P_FLAGS.PF_R else 0
+ instance |= __class__.W if p_flags & P_FLAGS.PF_W else 0
+ instance |= __class__.X if p_flags & P_FLAGS.PF_X else 0
+ return instance
+
+ class LoadFlags(IntFlag):
+ """ Type for describing the memory load flags of a region. """
+ NO_BITS = 0x01
+
+ def get_flags(self):
+ """ Queries the value of the flags in manifest format. """
+ return self.value
+
+ def is_compatible(self, other):
+ """ Return true of the other flags can be merged with self. """
+ return (self & self.NO_BITS) == (other & self.NO_BITS)
+
+ def __str__(self):
+ return ",".join([str(f.name) for f in __class__ if f in self])
+
+ def __init__(self, segment, section):
+ segment = segment.segment
+ sec_h = section.header
+ self.start_address = sec_h.sh_addr
+ self.end_address = sec_h.sh_addr + sec_h.sh_size
+ self.attributes = self.ManifestMemAttr.from_p_flags(segment.header.p_flags)
+ self.load_flags = self.LoadFlags(0)
+ self.load_flags |= self.LoadFlags.NO_BITS if sec_h.sh_type == "SHT_NOBITS" else 0
+ self.sections = [section.name]
+
+ def is_compatible_region(self, region):
+ """ Checks if the other region has compatible attributes/flags. """
+ return self.load_flags.is_compatible(region.load_flags)
+
+ def append_region(self, region):
+ """ Extends the region by the other region. """
+ self.end_address = region.end_address
+ self.sections += region.sections
+
+ def write_manifest(self, load_base_addr, manifest_file):
+ """
+ Writes the region into the manifest file. The address is adjusted by load_base_address.
+ """
+ manifest_file.write(f"{self.generate_region_name(load_base_addr)} {{\n")
+ manifest_file.write(f"\t/* {self.generate_section_list()} */\n")
+ manifest_file.write(f"\t{self.serialize_offset(load_base_addr)}\n")
+ manifest_file.write(f"\t{self.serialize_pages_count()}\n")
+ manifest_file.write(f"\t{self.serialize_attributes()}\n")
+ manifest_file.write(f"\t{self.serialize_load_flags()}\n")
+ manifest_file.write("};\n")
+
+ def generate_region_name(self, load_base_addr):
+ """ Generates a name for the region using the region_[start address] pattern. """
+ return f"region_{self.start_address - load_base_addr:x}"
+
+ def generate_section_list(self):
+ """ Lists the name of member sections of the region. """
+ return ", ".join(self.sections)
+
+ def serialize_offset(self, load_base_addr):
+ """ Calculates and outputs the offset of the region in manifest format. """
+ base = self.start_address - load_base_addr
+ end = self.end_address - load_base_addr
+ high, low = (base >> 32) & 0xffffffff, base & 0xffffffff
+ return f"load-address-relative-offset = <0x{high:x} 0x{low:x}>;\t" + \
+ f"/* 0x{base:x} - 0x{end:x} */"
+
+ def serialize_pages_count(self):
+ """ Calculates and outputs the page count of the region in manifest format. """
+ region_length = self.end_address - self.start_address
+ pages_count = ceil(region_length / ElfSegmentsToManifest.PAGE_SIZE)
+ return f"pages-count = <{pages_count}>;\t/* {region_length} bytes */"
+
+ def serialize_attributes(self):
+ """ Generates the memory region attribute value in manifest format. """
+ return f"attributes = <{self.attributes.get_attr()}>;\t/* {self.attributes} */"
+
+ def serialize_load_flags(self):
+ """ Generates the memory region load flags value in manifest format. """
+ return f"load-flags = <{self.load_flags.get_flags()}>;\t/* {self.load_flags} */"
+
+ class Segment:
+ """ Stores a segment and its sections. Able to produce a region list. """
+ def __init__(self, segment, sections):
+ def is_aligned(segment):
+ return segment.header.p_align == ElfSegmentsToManifest.PAGE_SIZE
+ assert is_aligned(segment), "Segments must be 4k aligned, check LD script"
+ self.segment = segment
+ self.sections = [s for s in sections if self.segment.section_in_segment(s)]
+ self.regions = []
+ self.merge_sections_to_regions()
+
+ def get_load_address(self):
+ """ Queries the load address of the region. """
+ return self.segment.header.p_vaddr
+
+ def merge_sections_to_regions(self):
+ """ Merges consecutive sections with comptabile attributes/flags into regions. """
+ current_region = None
+ for section in self.sections:
+ region = ElfSegmentsToManifest.Region(self, section)
+ if current_region and current_region.is_compatible_region(region):
+ current_region.append_region(region)
+ else:
+ self.regions.append(region)
+ current_region = region
+
+ def write_manifest(self, load_base_addr, manifest_file):
+ """ Writes the regions into the manifest file. """
+ for region in self.regions:
+ region.write_manifest(load_base_addr, manifest_file)
+
+ def __init__(self):
+ self.segments = []
+ self.load_base_addr = None
+
+ def read_elf(self, elf_file_fp):
+ """ Reads and parses the sections and segments of the ELF file. """
+ elf_file = ELFFile(elf_file_fp)
+ segments = elf_file.iter_segments()
+
+ def is_load(segment):
+ return segment.header.p_type == "PT_LOAD"
+ self.segments = [self.Segment(s, elf_file.iter_sections()) for s in segments if is_load(s)]
+ self.load_base_addr = min([s.get_load_address() for s in self.segments])
+
+ def write_manifest(self, manifest_file):
+ """ Writes the memory regions of each segment into the manifest. """
+ for segment in self.segments:
+ segment.write_manifest(self.load_base_addr, manifest_file)
+
+
+if __name__ == "__main__":
+ import sys
+
+ ELF_SEGMENTS_TO_MANIFEST = ElfSegmentsToManifest()
+
+ with open(sys.argv[1], "rb") as fp:
+ ELF_SEGMENTS_TO_MANIFEST.read_elf(fp)
+
+ with open(sys.argv[2], "wt", encoding="ascii") as fp:
+ ELF_SEGMENTS_TO_MANIFEST.write_manifest(fp)
diff --git a/tools/python/merge_json.py b/tools/python/merge_json.py
new file mode 100644
index 000000000..1479d8cb9
--- /dev/null
+++ b/tools/python/merge_json.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+
+"""
+Merge multiple json files in the order of the command line arguments.
+"""
+
+import argparse
+import json
+import os
+
+def update_relative_path(path, original_json_path, merged_json_path):
+ """
+ Update relative path according to its original and new base directory.
+ """
+ original_base_dir = os.path.dirname(original_json_path)
+ merged_base_dir = os.path.dirname(merged_json_path)
+
+ return os.path.relpath(original_base_dir + "/" + path, merged_base_dir)
+
+parser = argparse.ArgumentParser(
+ prog="merge_json",
+ description="Merge multiple JSON files into a single file.",
+ epilog="The merge happens in the order of command line arguments.")
+parser.add_argument("output", help="Output JSON file")
+parser.add_argument("inputs", nargs="+", help="Input JSON files")
+
+args = parser.parse_args()
+
+json_combined = {}
+
+for input_json_path in args.inputs:
+ print(f"Adding {input_json_path}")
+ with open(input_json_path, "rt", encoding="ascii") as f:
+ json_fragment = json.load(f)
+
+ # Align relative paths to merged JSON file's path
+ # The original JSON fragment and the merged JSON file might be placed
+ # in a different directory. This requires updating the relative paths
+ # in the JSON, so the merged file can have paths relative to itself.
+ keys = list(json_fragment.keys())
+ assert keys
+ sp = keys[0]
+
+ json_fragment[sp]["image"] = update_relative_path(
+ json_fragment[sp]["image"], input_json_path, args.output)
+ json_fragment[sp]["pm"] = update_relative_path(
+ json_fragment[sp]["pm"], input_json_path, args.output)
+
+ json_combined = {**json_combined, **json_fragment}
+
+with open(args.output, "wt", encoding="ascii") as f:
+ json.dump(json_combined, f, indent=4)
diff --git a/tools/python/requirements.txt b/tools/python/requirements.txt
new file mode 100644
index 000000000..81bf60526
--- /dev/null
+++ b/tools/python/requirements.txt
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+pyelftools==0.28
diff --git a/version.txt b/version.txt
index 6c6aa7cb0..afaf360d3 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-0.1.0 \ No newline at end of file
+1.0.0 \ No newline at end of file