From 1d6c7bb9773f76aa70ce65822fa001ff72892cd2 Mon Sep 17 00:00:00 2001 From: Vadim Bendebury Date: Thu, 28 Feb 2019 20:05:27 -0800 Subject: nvmem: test modifications to support the new scheme This patch includes changes to support testing of the new nvmem implementation. Making fizz compatible required duplicating a lot of functionality available in the test/ directory (fuzz/nvmem_tpm2_mock.c is very similar to test/nvmem_tpm2_mock.c), but I could not find an easy way to avoid it. BRANCH=cr50, cr50-mp BUG=b:69907320, b:129710256 CQ-DEPEND=CL:1496607 TEST=with the rest of the patches applied 'make buildall -j' succeeds, which confirms both test and fuzz success. Change-Id: Ife999b04d22f8ddbe9ea5d35f4c3e21f57592754 Signed-off-by: Vadim Bendebury Reviewed-on: https://chromium-review.googlesource.com/1450278 Reviewed-by: Andrey Pronin --- test/build.mk | 9 +- test/legacy_nvmem_dump.h | 1043 +++++++++++++++++++++++++++++ test/nvmem.c | 1655 ++++++++++++++++++++++++++++++++-------------- test/nvmem_test.h | 28 + test/nvmem_tpm2_mock.c | 377 +++++++++++ test/nvmem_vars.c | 538 --------------- test/nvmem_vars.tasklist | 17 - test/pinweaver.c | 84 +-- test/test_config.h | 64 +- 9 files changed, 2673 insertions(+), 1142 deletions(-) create mode 100644 test/legacy_nvmem_dump.h create mode 100644 test/nvmem_test.h create mode 100644 test/nvmem_tpm2_mock.c delete mode 100644 test/nvmem_vars.c delete mode 100644 test/nvmem_vars.tasklist (limited to 'test') diff --git a/test/build.mk b/test/build.mk index 979fc352fe..6900c97e3d 100644 --- a/test/build.mk +++ b/test/build.mk @@ -47,7 +47,6 @@ test-list-host += motion_angle_tablet test-list-host += motion_lid test-list-host += mutex test-list-host += nvmem -test-list-host += nvmem_vars test-list-host += pingpong test-list-host += pinweaver test-list-host += power_button @@ -105,8 +104,7 @@ motion_angle-y=motion_angle.o motion_angle_data_literals.o motion_common.o motion_angle_tablet-y=motion_angle_tablet.o motion_angle_data_literals_tablet.o motion_common.o motion_lid-y=motion_lid.o mutex-y=mutex.o -nvmem-y=nvmem.o -nvmem_vars-y=nvmem_vars.o +nvmem-y=nvmem.o nvmem_tpm2_mock.o pingpong-y=pingpong.o pinweaver-y=pinweaver.o power_button-y=power_button.o @@ -135,3 +133,8 @@ vboot-y=vboot.o float-y=fp.o fp-y=fp.o x25519-y=x25519.o + +TPM2_ROOT := $(CROS_WORKON_SRCROOT)/src/third_party/tpm2 +$(out)/RO/common/new_nvmem.o: CFLAGS += -I$(TPM2_ROOT) +$(out)/RO/test/nvmem.o: CFLAGS += -I$(TPM2_ROOT) +$(out)/RO/test/nvmem_tpm2_mock.o: CFLAGS += -I$(TPM2_ROOT) diff --git a/test/legacy_nvmem_dump.h b/test/legacy_nvmem_dump.h new file mode 100644 index 0000000000..6816673c23 --- /dev/null +++ b/test/legacy_nvmem_dump.h @@ -0,0 +1,1043 @@ +/* + * Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * This is a test NVMEM snapshot, it includes a couple of key,value pairs and + * a set of TPM reserved and evictable objects, as created after the first + * Chrome OS boot on a device. + * + * This binary dump is placed in a separate file not to free up the test file + * using it. + */ + 0x00, 0x65, 0x8e, 0x10, 0x80, 0xca, 0x52, 0x1e, 0x95, 0x81, 0x12, 0x4f, + 0x36, 0x78, 0x9a, 0x34, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x10, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x2d, 0x70, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00, 0xe1, 0xac, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x37, 0x01, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xbd, 0xfe, 0xff, 0xff, 0x85, 0xfc, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0xde, 0x01, 0x00, 0xb4, 0xde, 0x01, 0x00, + 0x9b, 0x0f, 0x06, 0x00, 0xbc, 0xde, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x5b, 0x15, 0xa1, 0x0a, 0x05, 0x12, 0x58, 0x84, 0xbf, 0xf6, 0xc9, 0xf3, + 0xdd, 0xb7, 0x26, 0xce, 0x56, 0x9e, 0x5f, 0x7a, 0xa8, 0xd4, 0x8a, 0x67, + 0x5c, 0x26, 0x35, 0x0e, 0xb2, 0x13, 0x2c, 0x79, 0x20, 0x00, 0x26, 0xca, + 0x7d, 0xb8, 0x1a, 0x1f, 0x0b, 0x5c, 0x0a, 0xf3, 0xb5, 0xe2, 0x6a, 0xec, + 0x1a, 0x0d, 0x90, 0x8b, 0x92, 0x3c, 0x07, 0xb0, 0x41, 0xb0, 0x27, 0x20, + 0x88, 0x33, 0xfe, 0x5c, 0xf2, 0x7b, 0x20, 0x00, 0x9e, 0xb7, 0xa2, 0x4c, + 0xad, 0x6c, 0xc0, 0x92, 0x92, 0xef, 0xbc, 0x56, 0x65, 0x47, 0xf9, 0x09, + 0xd1, 0xc4, 0xbc, 0x36, 0xe8, 0x3a, 0xc2, 0x8a, 0x11, 0x3a, 0xca, 0xe1, + 0x66, 0xd7, 0x85, 0x57, 0x20, 0x00, 0x0c, 0x6d, 0xc7, 0x61, 0x92, 0xfc, + 0x1b, 0x24, 0x02, 0xc1, 0x92, 0x0e, 0xf4, 0xa1, 0x75, 0xbe, 0xb1, 0x3d, + 0x29, 0xfe, 0x1e, 0xe2, 0x65, 0xf5, 0x25, 0xae, 0xaf, 0xfe, 0x73, 0x32, + 0x35, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x52, 0x01, 0x7b, 0x53, 0xc5, 0x95, 0xa0, 0x3a, 0x07, 0xd5, 0x62, 0x7f, + 0xd3, 0x9c, 0x85, 0xaa, 0xfc, 0x56, 0xa0, 0xfa, 0x3a, 0xe8, 0x17, 0x38, + 0xc3, 0x59, 0x65, 0xbe, 0x75, 0x1b, 0xdc, 0xdc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x84, 0xe7, 0x7e, 0x46, 0xfe, 0xbd, + 0x10, 0xdd, 0x5b, 0x09, 0xb2, 0xe2, 0xb1, 0x3f, 0xbf, 0x9a, 0xf3, 0xd7, + 0xfb, 0xf7, 0x28, 0xbb, 0x24, 0x10, 0xa3, 0xf3, 0x18, 0xa4, 0xa2, 0x16, + 0xd5, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x03, 0xff, 0xff, 0xff, 0x0b, 0x00, + 0x03, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x03, 0xff, 0xff, 0xff, 0x0d, 0x00, + 0x03, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, + 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + /* Manually added nonempty pcr. Array 0, index 0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + /* Manually added nonempty pcr. Array 1, index 1 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* Manually added ram index of size 0x20 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x69, 0x17, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, + 0xc0, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x20, 0x04, 0x62, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xef, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x01, 0x30, 0x82, 0x03, 0xeb, 0x30, 0x82, 0x02, 0xd3, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x10, 0x71, 0x7b, 0xc1, 0xfb, 0x3b, 0x21, 0xb5, + 0xfb, 0x02, 0x21, 0x1f, 0xb7, 0x0a, 0xbc, 0xe4, 0x88, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, + 0x61, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, + 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1b, 0x45, 0x6e, + 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, + 0x74, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x17, + 0x43, 0x52, 0x4f, 0x53, 0x20, 0x54, 0x50, 0x4d, 0x20, 0x50, 0x52, 0x44, + 0x20, 0x45, 0x4b, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x20, 0x43, 0x41, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x37, 0x30, 0x36, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x37, 0x30, 0x36, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x5a, 0x30, 0x00, 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, 0xf8, 0x26, 0xde, 0x99, 0xfa, 0x25, + 0xe1, 0xb6, 0xda, 0xb7, 0x88, 0x74, 0x77, 0x3d, 0x9a, 0x2e, 0xd0, 0xbd, + 0xda, 0x68, 0x8b, 0x1b, 0x8c, 0xe7, 0xd1, 0x0b, 0xf4, 0xfe, 0x8e, 0x94, + 0x09, 0x43, 0x11, 0x11, 0x46, 0xfc, 0x16, 0xb5, 0x15, 0x67, 0xab, 0x1b, + 0x8f, 0x25, 0xa7, 0x28, 0x04, 0xcc, 0xed, 0xf0, 0x5c, 0xbe, 0xa3, 0xfd, + 0x85, 0x85, 0x9b, 0xea, 0x6c, 0x61, 0x8b, 0x7e, 0xd2, 0x76, 0x2b, 0x37, + 0x87, 0x30, 0xd3, 0x9f, 0x0d, 0xb7, 0x0e, 0x31, 0x39, 0x3b, 0x3a, 0xa3, + 0xab, 0xb5, 0x21, 0x15, 0xb2, 0xc6, 0x7e, 0x78, 0xdc, 0x97, 0x53, 0x56, + 0x3f, 0xe9, 0xb4, 0x4e, 0xb8, 0xdd, 0x09, 0xa6, 0x37, 0xd3, 0xf7, 0x11, + 0xa2, 0x52, 0x50, 0xa6, 0x53, 0x44, 0xce, 0xb3, 0x9c, 0x02, 0xd8, 0x59, + 0x04, 0x3b, 0xba, 0x6c, 0xce, 0xf1, 0x6b, 0x33, 0x60, 0x14, 0x6b, 0xa0, + 0x3d, 0x2e, 0x66, 0x67, 0x82, 0x4f, 0x13, 0xa1, 0x82, 0xc4, 0x15, 0x08, + 0x7e, 0x59, 0xba, 0x84, 0x3e, 0xac, 0x12, 0x42, 0x98, 0x3d, 0x6e, 0xda, + 0xa9, 0xc3, 0xd7, 0x45, 0xeb, 0xc8, 0xec, 0x2a, 0x94, 0x9e, 0xc1, 0xf7, + 0x71, 0xca, 0x3d, 0xb3, 0xd2, 0x68, 0x2a, 0xc0, 0xbe, 0x9e, 0x2f, 0x26, + 0xf3, 0xf9, 0xb9, 0x7f, 0x21, 0x7f, 0x2f, 0x8b, 0x1b, 0x10, 0xb1, 0x09, + 0xc8, 0xab, 0xae, 0xda, 0xae, 0x66, 0x07, 0x4a, 0xc0, 0x75, 0x2a, 0x29, + 0x74, 0xb2, 0x99, 0xa6, 0x58, 0x84, 0xdc, 0x3e, 0x6b, 0x47, 0x37, 0xcb, + 0xb1, 0xc8, 0xcc, 0x81, 0xb3, 0x8b, 0x3a, 0x0c, 0xd4, 0x6a, 0x11, 0x3f, + 0x25, 0x17, 0x5d, 0xaf, 0x33, 0x8a, 0x32, 0x9d, 0x93, 0xef, 0xdb, 0x95, + 0x60, 0x5a, 0x15, 0xc5, 0x20, 0x7a, 0xec, 0xce, 0xa9, 0x31, 0x70, 0x24, + 0xd1, 0x4d, 0x29, 0xed, 0xeb, 0xec, 0xac, 0x53, 0x19, 0xc3, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x81, 0xdf, 0x30, 0x81, 0xdc, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x00, + 0x20, 0x30, 0x51, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01, 0xff, 0x04, + 0x47, 0x30, 0x45, 0xa4, 0x43, 0x30, 0x41, 0x31, 0x16, 0x30, 0x14, 0x06, + 0x05, 0x67, 0x81, 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69, 0x64, 0x3a, 0x34, + 0x37, 0x34, 0x46, 0x34, 0x46, 0x34, 0x37, 0x31, 0x0f, 0x30, 0x0d, 0x06, + 0x05, 0x67, 0x81, 0x05, 0x02, 0x02, 0x0c, 0x04, 0x48, 0x31, 0x42, 0x32, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67, 0x81, 0x05, 0x02, 0x03, 0x0c, + 0x0b, 0x69, 0x64, 0x3a, 0x30, 0x30, 0x31, 0x33, 0x30, 0x30, 0x33, 0x37, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, + 0x30, 0x00, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x0c, 0x30, + 0x0a, 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x02, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x15, 0x39, 0x34, 0xfc, 0x59, 0x19, 0xcd, 0x29, 0x82, 0xf1, 0xf4, 0x7f, + 0xad, 0x85, 0xd6, 0x44, 0x69, 0xa1, 0xa1, 0x7b, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x1d, 0x25, 0x04, 0x09, 0x30, 0x07, 0x06, 0x05, 0x67, 0x81, 0x05, + 0x08, 0x01, 0x30, 0x21, 0x06, 0x03, 0x55, 0x1d, 0x09, 0x04, 0x1a, 0x30, + 0x18, 0x30, 0x16, 0x06, 0x05, 0x67, 0x81, 0x05, 0x02, 0x10, 0x31, 0x0d, + 0x30, 0x0b, 0x0c, 0x03, 0x32, 0x2e, 0x30, 0x02, 0x01, 0x00, 0x02, 0x01, + 0x10, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x00, 0x1a, 0xef, + 0x74, 0x00, 0x05, 0xa3, 0x1c, 0x8c, 0xec, 0x0b, 0x6d, 0x67, 0x1b, 0x26, + 0x34, 0x62, 0xb3, 0x0c, 0x04, 0x34, 0xf6, 0x8c, 0x60, 0xa3, 0xcc, 0x5a, + 0xa7, 0x5f, 0x30, 0xa1, 0x50, 0x13, 0xb5, 0xf2, 0x83, 0x49, 0xfb, 0x35, + 0x01, 0x74, 0xde, 0xba, 0x3d, 0xba, 0x81, 0x0c, 0x87, 0x92, 0xbb, 0x20, + 0xc8, 0xe3, 0x4e, 0x15, 0xd4, 0x6d, 0xe6, 0x6f, 0xae, 0xca, 0x29, 0xa2, + 0xba, 0x5a, 0xac, 0xb9, 0x0c, 0xef, 0x85, 0xce, 0x6c, 0x03, 0xbd, 0x57, + 0x41, 0x90, 0x13, 0x68, 0x7b, 0xe0, 0x5e, 0xc6, 0x96, 0xe6, 0xbd, 0x67, + 0x62, 0x83, 0x7b, 0xc1, 0xa6, 0xfc, 0x2e, 0xc7, 0x74, 0x54, 0xef, 0x93, + 0x28, 0x8b, 0x1f, 0x73, 0x3c, 0xa9, 0x11, 0x6e, 0xac, 0xdf, 0x9e, 0xe2, + 0xb5, 0x6d, 0x62, 0x44, 0xc3, 0xa0, 0xf6, 0x82, 0x7b, 0x23, 0x82, 0x73, + 0x91, 0x22, 0x11, 0x7b, 0xb8, 0x8a, 0x19, 0x45, 0x2b, 0x99, 0xdc, 0x7a, + 0xa1, 0x21, 0xd8, 0x37, 0x51, 0x60, 0xfb, 0x20, 0xab, 0x2d, 0x6c, 0x32, + 0x07, 0xb8, 0x15, 0xed, 0x7c, 0x62, 0xe9, 0xc9, 0x1d, 0x50, 0x6c, 0x6c, + 0x1b, 0x55, 0xcd, 0x92, 0xb6, 0xc1, 0x9a, 0x3d, 0xac, 0x01, 0xc0, 0x66, + 0xca, 0xc1, 0x91, 0x09, 0x50, 0x4d, 0x1a, 0xc0, 0x6f, 0xe3, 0x2d, 0x4b, + 0x7f, 0xee, 0xa9, 0xff, 0xeb, 0x0d, 0x5d, 0xe5, 0x64, 0xfd, 0x52, 0x6e, + 0x8a, 0x91, 0x2d, 0xd0, 0x13, 0xf5, 0xcd, 0x32, 0xfb, 0xe2, 0xe7, 0x6d, + 0xfb, 0x05, 0x6a, 0x2a, 0xec, 0xc8, 0xa6, 0xd3, 0x94, 0xee, 0x89, 0x40, + 0x24, 0x39, 0x84, 0x6a, 0xc1, 0xd4, 0x16, 0xdf, 0x0f, 0x79, 0x3b, 0x57, + 0x17, 0x4d, 0x2d, 0x58, 0x65, 0x19, 0xce, 0x0c, 0xf4, 0x86, 0x19, 0xa6, + 0xfe, 0xd7, 0xac, 0x7c, 0x15, 0x7d, 0x06, 0x08, 0xd2, 0xb6, 0xb9, 0x5e, + 0x00, 0x29, 0x1b, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x01, 0x00, 0xc0, + 0x01, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x20, 0x04, 0x62, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x01, 0x30, 0x82, 0x03, 0x20, 0x30, 0x82, 0x02, 0x08, 0xa0, 0x03, 0x02, + 0x01, 0x02, 0x02, 0x10, 0x64, 0x2e, 0x3d, 0x44, 0xaa, 0x6d, 0x90, 0x95, + 0x42, 0x28, 0x7d, 0x07, 0x5e, 0xe7, 0x68, 0x66, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, + 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x24, + 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1b, 0x45, 0x6e, 0x67, + 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, + 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x17, 0x43, + 0x52, 0x4f, 0x53, 0x20, 0x54, 0x50, 0x4d, 0x20, 0x50, 0x52, 0x44, 0x20, + 0x45, 0x4b, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x38, 0x30, 0x37, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x37, 0x30, 0x36, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x32, 0x5a, 0x30, 0x00, 0x30, 0x59, 0x30, 0x13, + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xad, + 0x72, 0x36, 0x6c, 0x76, 0x5e, 0x69, 0xa1, 0xf5, 0xeb, 0xbf, 0x5d, 0x38, + 0x1d, 0x76, 0xda, 0xb3, 0x80, 0xf6, 0xa8, 0xf3, 0x2c, 0x42, 0x7e, 0xc8, + 0xd7, 0xc9, 0x46, 0xbd, 0xc6, 0x80, 0x7f, 0xd3, 0xf4, 0xac, 0xa5, 0x60, + 0xa3, 0xf1, 0x31, 0x6c, 0xdf, 0x87, 0x95, 0x5c, 0xb6, 0xf3, 0x79, 0xff, + 0x7b, 0x46, 0x53, 0xec, 0x3f, 0x20, 0xde, 0x59, 0xa5, 0x2d, 0xcb, 0x77, + 0x55, 0x89, 0xad, 0xa3, 0x81, 0xdf, 0x30, 0x81, 0xdc, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x00, + 0x20, 0x30, 0x51, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01, 0xff, 0x04, + 0x47, 0x30, 0x45, 0xa4, 0x43, 0x30, 0x41, 0x31, 0x16, 0x30, 0x14, 0x06, + 0x05, 0x67, 0x81, 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69, 0x64, 0x3a, 0x34, + 0x37, 0x34, 0x46, 0x34, 0x46, 0x34, 0x37, 0x31, 0x0f, 0x30, 0x0d, 0x06, + 0x05, 0x67, 0x81, 0x05, 0x02, 0x02, 0x0c, 0x04, 0x48, 0x31, 0x42, 0x32, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67, 0x81, 0x05, 0x02, 0x03, 0x0c, + 0x0b, 0x69, 0x64, 0x3a, 0x30, 0x30, 0x31, 0x33, 0x30, 0x30, 0x33, 0x37, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, + 0x30, 0x00, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x0c, 0x30, + 0x0a, 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x02, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x15, 0x39, 0x34, 0xfc, 0x59, 0x19, 0xcd, 0x29, 0x82, 0xf1, 0xf4, 0x7f, + 0xad, 0x85, 0xd6, 0x44, 0x69, 0xa1, 0xa1, 0x7b, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x1d, 0x25, 0x04, 0x09, 0x30, 0x07, 0x06, 0x05, 0x67, 0x81, 0x05, + 0x08, 0x01, 0x30, 0x21, 0x06, 0x03, 0x55, 0x1d, 0x09, 0x04, 0x1a, 0x30, + 0x18, 0x30, 0x16, 0x06, 0x05, 0x67, 0x81, 0x05, 0x02, 0x10, 0x31, 0x0d, + 0x30, 0x0b, 0x0c, 0x03, 0x32, 0x2e, 0x30, 0x02, 0x01, 0x00, 0x02, 0x01, + 0x10, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3a, 0xe0, 0x1e, + 0x15, 0xd7, 0x11, 0x97, 0xc6, 0xc3, 0x50, 0x9a, 0x0b, 0x7f, 0x0a, 0x5e, + 0x7d, 0xd2, 0xb8, 0x08, 0xc0, 0x98, 0x35, 0x73, 0x6d, 0x85, 0x19, 0x46, + 0x76, 0x27, 0xcb, 0xa3, 0x66, 0x7f, 0xc9, 0x26, 0x20, 0x52, 0xb5, 0xe9, + 0xf5, 0xa0, 0x7a, 0x1d, 0xb3, 0x78, 0x66, 0x6d, 0x13, 0xcb, 0x82, 0x5b, + 0x09, 0xdc, 0xcb, 0x01, 0x0c, 0x3e, 0x34, 0x4a, 0x92, 0x44, 0x30, 0x44, + 0xda, 0x49, 0xad, 0x45, 0x17, 0xc3, 0x5b, 0x80, 0x8c, 0xa5, 0x11, 0xc4, + 0x07, 0x1a, 0x06, 0x43, 0x9c, 0x57, 0x51, 0x42, 0x35, 0xfd, 0xec, 0x68, + 0xe3, 0xe8, 0x3f, 0x5b, 0xb0, 0x01, 0x4f, 0xcb, 0xe0, 0x2a, 0x7f, 0xe6, + 0x89, 0xcc, 0xef, 0x59, 0xbb, 0x11, 0xed, 0xcb, 0xe6, 0xc9, 0x55, 0x94, + 0xf0, 0x5b, 0xee, 0x33, 0xc9, 0xed, 0x1b, 0x02, 0xeb, 0x90, 0x33, 0x0e, + 0xc1, 0x8f, 0x1c, 0x37, 0x3f, 0x9c, 0x59, 0x96, 0xe7, 0x73, 0xb1, 0x90, + 0x7a, 0x93, 0x2f, 0x4e, 0x98, 0xff, 0xff, 0xa7, 0xfb, 0x7f, 0xb9, 0x1b, + 0x46, 0xb8, 0x64, 0x12, 0x92, 0x74, 0x54, 0xe1, 0x7f, 0x07, 0xfa, 0xc4, + 0x2e, 0x53, 0xa8, 0x6a, 0xe5, 0x23, 0x92, 0x9e, 0x39, 0x37, 0xfc, 0x5d, + 0x2f, 0x7b, 0x69, 0x84, 0xd3, 0x69, 0x4e, 0xd1, 0x98, 0xda, 0x53, 0x34, + 0x80, 0xe6, 0xeb, 0xd5, 0x9a, 0x10, 0x5d, 0xc9, 0x88, 0x2b, 0x13, 0x9c, + 0xb9, 0xad, 0x15, 0x4f, 0x3a, 0x6c, 0x0d, 0xd4, 0x50, 0x0b, 0x1d, 0xfb, + 0x36, 0x74, 0xf2, 0x3e, 0x32, 0xce, 0x69, 0x5f, 0x67, 0x63, 0x33, 0x0f, + 0x7b, 0xc9, 0x5e, 0x68, 0x39, 0xdf, 0xb9, 0xe2, 0x73, 0xd5, 0xd5, 0x40, + 0xd8, 0x62, 0x0a, 0x4e, 0x45, 0x6f, 0xc1, 0x92, 0x9c, 0x41, 0x58, 0x21, + 0xd4, 0x60, 0x0b, 0xc4, 0x7c, 0x9c, 0xe8, 0x57, 0x5c, 0xed, 0xbc, 0xc1, + 0xf4, 0x51, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc3, 0x3c, 0x43, + 0xf2, 0xe7, 0x82, 0xf3, 0x5c, 0xec, 0x61, 0x96, 0xef, 0xf5, 0xfb, 0x24, + 0x87, 0xaa, 0xf9, 0x5f, 0x3f, 0xf6, 0x5e, 0xdd, 0x0a, 0x59, 0x33, 0xbb, + 0xe1, 0xaf, 0x3b, 0xb2, 0x26, 0xfa, 0x1b, 0x00, 0x00, 0x08, 0x10, 0x00, + 0x01, 0x08, 0x10, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, + 0x60, 0x00, 0x00, 0x00, 0xe0, 0xd7, 0xdd, 0x01, 0x00, 0xe3, 0xad, 0x05, + 0x00, 0xe2, 0xad, 0x05, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x53, 0x07, + 0x00, 0x00, 0x53, 0x07, 0x00, 0x30, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd7, 0xdd, 0x01, 0x00, 0xd3, 0x3a, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb0, 0xde, 0x01, 0x00, 0xb4, 0xde, 0x01, 0x00, 0x9b, 0x0f, 0x06, + 0x00, 0xbc, 0xde, 0x01, 0x00, 0x40, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x8c, 0xb5, 0x01, 0x00, 0xd7, 0xdd, 0x01, + 0x00, 0x1f, 0xbd, 0x05, 0x00, 0x4e, 0xbd, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x41, 0x01, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x19, 0x53, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x4c, 0x57, 0x52, 0x47, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xa0, 0x1c, 0x00, 0x00, 0x07, 0x10, + 0x00, 0x01, 0x07, 0x10, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x4c, + 0x05, 0x60, 0x20, 0x00, 0x09, 0x93, 0x3c, 0xce, 0xeb, 0xb4, 0x41, 0x11, + 0x18, 0x81, 0x1d, 0xd4, 0x47, 0x78, 0x80, 0x08, 0x88, 0x86, 0x62, 0x2d, + 0xd7, 0x79, 0x94, 0x46, 0x62, 0x26, 0x68, 0x8e, 0xee, 0xe6, 0x6a, 0xa1, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb0, 0xde, 0x01, 0x00, 0xb4, 0xde, 0x01, 0x00, 0x9b, 0x0f, + 0x06, 0x00, 0xbc, 0xde, 0x01, 0x00, 0x40, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x8c, 0xb5, 0x01, 0x00, 0xd7, 0xdd, + 0x01, 0x00, 0x1f, 0xbd, 0x05, 0x00, 0x4e, 0xbd, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x41, 0x01, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x19, 0x53, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x4f, 0x64, 0x1d, 0x00, 0x00, 0x05, 0x00, 0x80, 0x01, + 0x05, 0x00, 0x80, 0x01, 0x0b, 0x00, 0x01, 0x00, 0x04, 0x28, 0x04, 0xb0, + 0x00, 0x00, 0x40, 0x00, 0xcd, 0xd4, 0x97, 0x24, 0x1f, 0x26, 0xd9, 0x91, + 0xad, 0xb8, 0xd2, 0xcb, 0x46, 0x14, 0x65, 0x72, 0x91, 0x8d, 0x56, 0x2e, + 0x7b, 0x3f, 0x74, 0x89, 0x80, 0xc6, 0x18, 0xbf, 0xea, 0x58, 0xe6, 0xf6, + 0x54, 0xde, 0x01, 0x00, 0xaa, 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb0, 0xde, 0x01, 0x00, 0xb4, 0xde, 0x01, 0x00, 0x9b, 0x0f, 0x06, 0x00, + 0xbc, 0xde, 0x01, 0x00, 0x40, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xfe, 0x1b, 0x00, 0x00, 0x05, 0x00, 0x80, 0x01, 0x43, 0xcf, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x10, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0xf0, 0xde, 0x01, 0x00, 0x69, 0x01, 0x00, 0x00, 0xb3, 0xd3, 0x05, 0x00, + 0xa4, 0xde, 0x01, 0x00, 0xa8, 0xde, 0x01, 0x00, 0xf4, 0xde, 0x01, 0x00, + 0xd1, 0x73, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xde, 0x40, 0x00, + 0x78, 0x04, 0x01, 0x00, 0x32, 0x4d, 0x50, 0x54, 0x01, 0x00, 0x00, 0x00, + 0xe0, 0xa7, 0x0d, 0x1e, 0x0d, 0xe2, 0x5a, 0xb8, 0xd4, 0x5e, 0xb8, 0x2b, + 0xcc, 0x99, 0xd2, 0x6a, 0x8f, 0xf0, 0x52, 0x18, 0x72, 0x02, 0x16, 0x8e, + 0x83, 0x06, 0xba, 0x01, 0xe4, 0xcc, 0xbf, 0xcf, 0x80, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x81, 0x38, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, + 0x00, 0x03, 0x04, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x00, 0x43, + 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x9b, 0x0f, + 0x10, 0x85, 0x8c, 0x80, 0xfc, 0x15, 0x23, 0xeb, 0x29, 0x04, 0x2d, 0x2c, + 0xfc, 0xed, 0xc4, 0x1e, 0x3f, 0xf3, 0xc2, 0x3f, 0x42, 0xd0, 0x5c, 0x8d, + 0xe7, 0x3f, 0xc3, 0x17, 0x6d, 0xc5, 0x2c, 0xa8, 0x5f, 0x29, 0x80, 0x82, + 0xf2, 0x1f, 0xd1, 0x48, 0xfc, 0x50, 0x96, 0x51, 0x13, 0x5f, 0xbf, 0xa0, + 0xdf, 0xb0, 0x16, 0xe2, 0x80, 0x54, 0x11, 0x10, 0x7d, 0x05, 0xf6, 0x16, + 0x07, 0xd3, 0xbe, 0x8e, 0x16, 0x6c, 0x83, 0x56, 0xdc, 0xd9, 0x0d, 0x29, + 0x42, 0x26, 0x37, 0xa0, 0x5a, 0xa0, 0x47, 0x02, 0x80, 0xfd, 0x2c, 0x8c, + 0x23, 0x6c, 0x96, 0x44, 0x9f, 0xd6, 0x7e, 0x33, 0x70, 0xd0, 0xe7, 0x3c, + 0x93, 0xf6, 0x4c, 0xf3, 0xf9, 0x6f, 0x5d, 0x40, 0xa0, 0xb0, 0xf5, 0x69, + 0xcc, 0x60, 0x19, 0x83, 0x0b, 0xe1, 0xc6, 0xc7, 0x8b, 0xa1, 0x3a, 0x01, + 0x16, 0x68, 0xd6, 0x28, 0xf9, 0x19, 0xee, 0x2b, 0x74, 0x9a, 0xba, 0xac, + 0x5e, 0x4e, 0x8d, 0x1d, 0x86, 0xef, 0xaf, 0xa4, 0xb4, 0xbd, 0xd4, 0x97, + 0x08, 0x6f, 0x20, 0x9b, 0xb3, 0xe8, 0x5e, 0x43, 0x9e, 0xad, 0x05, 0xf8, + 0xf0, 0x18, 0x53, 0xaf, 0xda, 0xb7, 0xbc, 0xe1, 0x43, 0xda, 0x03, 0xc0, + 0xe4, 0x5a, 0xd1, 0x74, 0xc4, 0x63, 0x2c, 0x22, 0x64, 0x34, 0x61, 0x07, + 0x26, 0x3d, 0x8c, 0x91, 0x29, 0xcc, 0x22, 0x5f, 0x14, 0xe9, 0xef, 0x7e, + 0xbb, 0x80, 0xf3, 0xed, 0x35, 0xbb, 0xf9, 0xca, 0xa5, 0x53, 0xff, 0x47, + 0x9d, 0xc7, 0xf4, 0x1e, 0xfe, 0x24, 0xf1, 0xbd, 0x30, 0x3e, 0x4c, 0xd6, + 0x47, 0x2c, 0x00, 0x16, 0x78, 0x61, 0xc4, 0x72, 0xb1, 0x39, 0xe1, 0x5d, + 0x18, 0x10, 0xa4, 0x1c, 0x4e, 0x42, 0x27, 0xe4, 0xd2, 0x4b, 0xcb, 0x65, + 0x2f, 0x33, 0x69, 0x49, 0xca, 0x2a, 0x89, 0xc7, 0x5d, 0xca, 0x7e, 0xfd, + 0xf2, 0x6b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x73, 0x9a, 0x3e, 0x61, + 0x92, 0x20, 0x63, 0x87, 0x6e, 0x99, 0xaa, 0x85, 0x7b, 0x24, 0x5e, 0xee, + 0xfe, 0x80, 0x4d, 0xaa, 0x66, 0x1e, 0x2b, 0xe6, 0x69, 0xca, 0x1f, 0xfd, + 0x41, 0xe8, 0x0e, 0xca, 0x00, 0x80, 0xc5, 0xdf, 0xa6, 0x9d, 0x5a, 0x23, + 0xde, 0xc4, 0x38, 0xfe, 0xd0, 0x80, 0x5e, 0x7d, 0xd3, 0x01, 0x07, 0xa3, + 0x93, 0x80, 0x19, 0xb8, 0xf4, 0xaa, 0xb1, 0xf4, 0x09, 0x78, 0x91, 0x52, + 0x48, 0xb1, 0x2b, 0x1b, 0xab, 0xcc, 0x60, 0x53, 0x20, 0x92, 0x85, 0xc6, + 0xf7, 0xff, 0x08, 0xee, 0x68, 0x6c, 0xfd, 0x3e, 0xd6, 0x9d, 0xda, 0x0d, + 0x03, 0x0c, 0x7c, 0xe0, 0x2b, 0x5c, 0xd4, 0x35, 0x9b, 0x3d, 0x7d, 0xd4, + 0x07, 0x7c, 0x8a, 0xc3, 0x79, 0xc0, 0x4b, 0x52, 0x20, 0x18, 0x2f, 0xfe, + 0x19, 0xe6, 0x41, 0xac, 0x31, 0xef, 0x32, 0x8e, 0x47, 0xdf, 0x0b, 0x8d, + 0x6b, 0x50, 0xbe, 0x15, 0xa2, 0x17, 0x51, 0xef, 0x5e, 0x87, 0xc3, 0x2e, + 0xd8, 0xf8, 0xb7, 0x72, 0xc9, 0x5d, 0xe8, 0x71, 0xef, 0x32, 0x02, 0x5d, + 0xc5, 0x49, 0x4e, 0xb7, 0xb8, 0xdc, 0xe3, 0x9d, 0xcb, 0x29, 0x49, 0x90, + 0xcf, 0xdf, 0x00, 0x00, 0x00, 0x22, 0x00, 0x0b, 0x96, 0xce, 0xc6, 0x42, + 0x3b, 0x6f, 0x58, 0x90, 0xd2, 0x2a, 0xbc, 0xc4, 0x59, 0xa1, 0xfb, 0x63, + 0xc4, 0xef, 0x59, 0x2a, 0x2d, 0x92, 0x76, 0xfa, 0xdb, 0xac, 0xf6, 0x7b, + 0x77, 0xb7, 0x56, 0x93, 0x81, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x0b, + 0x68, 0x0f, 0x54, 0x0a, 0x3f, 0x27, 0xdc, 0x66, 0x76, 0x1a, 0x35, 0x71, + 0xe2, 0x5c, 0x08, 0xcf, 0xac, 0x39, 0xea, 0xcc, 0x01, 0x54, 0x4e, 0x48, + 0xaa, 0xe1, 0x5c, 0xa5, 0xb7, 0xe1, 0x5b, 0x50, 0x7c, 0x20, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x81, 0x38, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x0b, + 0x00, 0x03, 0x04, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x00, 0x43, + 0x00, 0x10, 0x00, 0x03, 0x00, 0x10, 0x00, 0x20, 0x6c, 0x05, 0x79, 0x5e, + 0x36, 0x4a, 0x04, 0x2c, 0x10, 0x8e, 0x50, 0xcc, 0x60, 0x7e, 0x18, 0xa1, + 0xe5, 0x4a, 0x96, 0x56, 0xf1, 0x5f, 0x34, 0x95, 0x36, 0xea, 0x00, 0x64, + 0xb9, 0xf4, 0x49, 0x91, 0x00, 0x20, 0x7f, 0x8c, 0xad, 0xea, 0x97, 0xba, + 0x99, 0x28, 0x93, 0xb4, 0xcc, 0xa7, 0x36, 0xfa, 0x61, 0xd8, 0x78, 0xb6, + 0x06, 0xcd, 0xe3, 0x27, 0x99, 0x7b, 0xaa, 0x3e, 0xa9, 0x4e, 0xf2, 0x93, + 0x18, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x16, 0xba, 0x08, 0xd2, + 0xd8, 0x63, 0x38, 0xba, 0xb9, 0x0b, 0xce, 0x5b, 0x72, 0x9a, 0x88, 0x08, + 0x25, 0xb9, 0xbd, 0xab, 0x16, 0x77, 0x43, 0xbb, 0xcd, 0x3d, 0x4d, 0x48, + 0xbc, 0x77, 0xf8, 0xd3, 0x00, 0x20, 0x0f, 0xd6, 0x89, 0x31, 0xdc, 0xfa, + 0x70, 0x00, 0x6a, 0x4b, 0x59, 0x60, 0x28, 0x01, 0x54, 0x39, 0x4e, 0xa1, + 0x97, 0x28, 0xe0, 0x84, 0x92, 0x0e, 0x35, 0xdc, 0xb3, 0x9a, 0x11, 0x08, + 0x7c, 0x93, 0x00, 0x00, 0x00, 0x22, 0x00, 0x0b, 0x5d, 0xab, 0xa0, 0x5d, + 0x70, 0x5f, 0x6e, 0x78, 0xeb, 0x82, 0x8c, 0xb4, 0x77, 0x45, 0x95, 0x50, + 0x6b, 0x7c, 0x97, 0x5d, 0x2d, 0x31, 0x76, 0x0e, 0x81, 0x9e, 0x4b, 0xa3, + 0x80, 0xf5, 0xff, 0x86, 0x81, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x0b, + 0x85, 0xf4, 0xbe, 0x91, 0xe1, 0x2b, 0x4c, 0x2d, 0xaa, 0x64, 0xb1, 0x90, + 0x5f, 0xec, 0x74, 0xea, 0xec, 0x2c, 0x3d, 0x0d, 0xbb, 0x26, 0xc0, 0x49, + 0x3d, 0xae, 0xa0, 0xe4, 0x72, 0xfa, 0xba, 0x15, 0x74, 0x22, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x81, 0x18, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, + 0x00, 0x02, 0x04, 0x72, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xed, 0x72, 0x50, 0x56, 0x10, 0xb7, + 0xab, 0x52, 0x50, 0x32, 0x4f, 0x82, 0x87, 0x94, 0x83, 0x84, 0x55, 0xeb, + 0xda, 0x78, 0x46, 0x34, 0x48, 0xc4, 0xc6, 0x28, 0x47, 0xf4, 0x4c, 0xfd, + 0x1f, 0x04, 0xcd, 0xb9, 0x72, 0x6a, 0x49, 0x6c, 0x1c, 0x9b, 0x07, 0x5b, + 0xe8, 0xef, 0xaf, 0x0b, 0xeb, 0xb1, 0xcb, 0x24, 0x0e, 0x63, 0x2f, 0x35, + 0x3c, 0x79, 0x0c, 0xde, 0xf5, 0xdb, 0x06, 0xe9, 0x68, 0xf4, 0xf0, 0x8e, + 0xf1, 0xbf, 0x98, 0x9a, 0xd9, 0x2b, 0x45, 0x85, 0x83, 0xda, 0xd9, 0xf3, + 0x6f, 0x1a, 0x24, 0xe8, 0x5d, 0xad, 0xda, 0xa7, 0xfc, 0x03, 0x67, 0xb0, + 0xdf, 0x07, 0xbd, 0xe1, 0x1e, 0x7d, 0xa1, 0xea, 0x59, 0xfb, 0xb9, 0x48, + 0x2d, 0x45, 0x0c, 0x1b, 0x52, 0x0e, 0xb3, 0xe6, 0xac, 0x4a, 0x91, 0x1c, + 0xb1, 0x2f, 0xee, 0xae, 0xf4, 0x0a, 0x79, 0x81, 0x92, 0xab, 0xaa, 0xff, + 0x44, 0x0f, 0x8d, 0xe7, 0x30, 0xfd, 0xee, 0x62, 0x0f, 0x92, 0x4d, 0x08, + 0xe7, 0xd0, 0xdb, 0x16, 0xf2, 0x27, 0x73, 0x59, 0x18, 0xc5, 0xd9, 0x0d, + 0xac, 0xaf, 0xc0, 0xd0, 0xdc, 0xfd, 0x1d, 0xeb, 0x74, 0x33, 0x59, 0xd6, + 0x30, 0xe1, 0x29, 0x81, 0xa5, 0xeb, 0x67, 0xc6, 0x32, 0x98, 0x37, 0x12, + 0xe8, 0x12, 0x3c, 0x5b, 0xd1, 0xc7, 0x9e, 0x9d, 0x5b, 0xe3, 0x7d, 0x5c, + 0xf6, 0x9e, 0x4d, 0xdf, 0x65, 0xe1, 0x95, 0x14, 0xf6, 0xda, 0x94, 0x91, + 0x76, 0x91, 0x6b, 0x39, 0x37, 0xf0, 0x72, 0xf9, 0x7f, 0xc1, 0x09, 0x9d, + 0x33, 0xf5, 0x26, 0x84, 0xe2, 0xa2, 0x94, 0xc3, 0xad, 0x4a, 0xc2, 0x86, + 0xa0, 0x1a, 0xf2, 0x0e, 0xa1, 0x98, 0xb1, 0x9f, 0x50, 0x54, 0xd5, 0xc8, + 0x58, 0x11, 0xc3, 0x76, 0x63, 0xc0, 0x49, 0x7b, 0xa5, 0x80, 0x79, 0x75, + 0xc0, 0x0c, 0xe9, 0x8a, 0xb0, 0xbe, 0x09, 0x54, 0xfa, 0x19, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xfa, 0x82, 0xd6, 0x21, 0xf1, 0x41, + 0x7e, 0xca, 0x35, 0x00, 0x73, 0x63, 0x3f, 0x8d, 0x38, 0xbd, 0x4d, 0xd0, + 0x27, 0x0d, 0xe2, 0x66, 0xa5, 0x3c, 0x47, 0x14, 0xe7, 0x36, 0x38, 0x87, + 0xe2, 0x5d, 0x6d, 0x2a, 0x19, 0x10, 0xee, 0xfe, 0xf1, 0x6d, 0x6d, 0xb5, + 0x2c, 0x2f, 0xe3, 0x8f, 0x9b, 0x5f, 0x73, 0x8b, 0xdd, 0x1b, 0x0d, 0xe8, + 0x81, 0x53, 0x79, 0x9b, 0xca, 0x86, 0x03, 0xf9, 0x2d, 0x6e, 0x85, 0x26, + 0x14, 0xa7, 0x71, 0xd5, 0xf8, 0xd8, 0x30, 0x27, 0x26, 0x08, 0x30, 0x17, + 0xf8, 0xc2, 0x17, 0x6a, 0xb3, 0x7e, 0x98, 0x69, 0x19, 0x94, 0x51, 0x34, + 0x94, 0x3c, 0xcf, 0x45, 0x9a, 0x9d, 0x9d, 0xea, 0xcf, 0x04, 0x74, 0x74, + 0x79, 0x09, 0x3f, 0xa0, 0xaa, 0x25, 0xd2, 0xda, 0x1f, 0x1a, 0xc6, 0x87, + 0xcf, 0x17, 0x1c, 0xfc, 0x1d, 0x59, 0x4e, 0x6d, 0x2f, 0x32, 0x28, 0x39, + 0xb0, 0xcd, 0x00, 0x00, 0x00, 0x22, 0x00, 0x0b, 0x92, 0x80, 0x9c, 0x28, + 0xa0, 0xc7, 0x75, 0x91, 0x80, 0xc9, 0x86, 0x63, 0xe1, 0xa7, 0x19, 0x33, + 0x21, 0xd8, 0x47, 0x8c, 0xac, 0xd4, 0x51, 0x7d, 0x78, 0x31, 0x84, 0x74, + 0x49, 0x63, 0x40, 0xba, 0x81, 0x00, 0x00, 0x02, 0x00, 0x22, 0x00, 0x0b, + 0xe9, 0x80, 0x8e, 0x73, 0x7d, 0xaa, 0xc3, 0xf8, 0x84, 0xaf, 0x7d, 0x18, + 0x10, 0x7c, 0xed, 0xf3, 0x14, 0x72, 0x61, 0x97, 0xb6, 0xd7, 0xbb, 0x3a, + 0x47, 0xb0, 0x91, 0xb0, 0xba, 0x7c, 0xbc, 0x04, 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, + 0x01, 0x20, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x12, 0x00, 0x76, 0x61, 0x72, 0x31, 0x74, 0x68, 0x69, 0x73, 0x5f, + 0x69, 0x73, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x31, 0x04, 0x12, 0x00, 0x76, 0x61, 0x72, 0x32, 0x74, 0x68, 0x69, 0x73, + 0x5f, 0x69, 0x73, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x32, 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, diff --git a/test/nvmem.c b/test/nvmem.c index 99b2d554e9..2b814251c9 100644 --- a/test/nvmem.c +++ b/test/nvmem.c @@ -5,11 +5,15 @@ * Test Cr-50 Non-Voltatile memory module */ +#include "nvmem_test.h" + #include "common.h" #include "console.h" #include "crc.h" -#include "nvmem.h" #include "flash.h" +#include "new_nvmem.h" +#include "nvmem.h" +#include "printf.h" #include "shared_mem.h" #include "task.h" #include "test_util.h" @@ -19,16 +23,29 @@ #define WRITE_SEGMENT_LEN 200 #define WRITE_READ_SEGMENTS 4 -uint32_t nvmem_user_sizes[NVMEM_NUM_USERS] = { - NVMEM_USER_0_SIZE, - NVMEM_USER_1_SIZE, - NVMEM_USER_2_SIZE +enum test_failure_mode failure_mode; + +static const uint8_t legacy_nvmem_image[] = { +#include "legacy_nvmem_dump.h" }; +BUILD_ASSERT(sizeof(legacy_nvmem_image) == NVMEM_PARTITION_SIZE); + static uint8_t write_buffer[NVMEM_PARTITION_SIZE]; -static uint8_t read_buffer[NVMEM_PARTITION_SIZE]; static int flash_write_fail; -static int lock_test_started; + +struct nvmem_test_result { + int var_count; + int reserved_obj_count; + int evictable_obj_count; + int deleted_obj_count; + int delimiter_count; + int unexpected_count; + size_t valid_data_size; + size_t erased_data_size; +}; + +static struct nvmem_test_result test_result; int app_cipher(const void *salt_p, void *out_p, const void *in_p, size_t size) { @@ -50,15 +67,28 @@ void app_compute_hash(uint8_t *p_buf, size_t num_bytes, uint32_t crc; uint32_t *p_data; int n; + size_t tail_size; crc32_init(); - /* Assuming here that buffer is 4 byte aligned and that num_bytes is - * divisible by 4 - */ + /* Assuming here that buffer is 4 byte aligned. */ p_data = (uint32_t *)p_buf; - for (n = 0; n < num_bytes/4; n++) + for (n = 0; n < num_bytes / 4; n++) crc32_hash32(*p_data++); - crc = crc32_result(); + + tail_size = num_bytes % 4; + if (tail_size) { + uint32_t tail; + + tail = 0; + memcpy(&tail, p_data, tail_size); + crc32_hash32(tail); + } + + /* + * Crc32 of 0xffffffff is 0xffffffff. Let's spike the results to avoid + * this unfortunate Crc32 property. + */ + crc = crc32_result() ^ 0x55555555; for (n = 0; n < hash_bytes; n += sizeof(crc)) { size_t copy_bytes = MIN(sizeof(crc), hash_bytes - n); @@ -73,652 +103,1263 @@ int flash_pre_op(void) return flash_write_fail ? EC_ERROR_UNKNOWN : EC_SUCCESS; } -static int generate_random_data(int offset, int num_bytes) +static void dump_nvmem_state(const char *title, + const struct nvmem_test_result *tr) +{ + ccprintf("\n%s:\n", title); + ccprintf("var_count: %d\n", tr->var_count); + ccprintf("reserved_obj_count: %d\n", tr->reserved_obj_count); + ccprintf("evictable_obj_count: %d\n", tr->evictable_obj_count); + ccprintf("deleted_obj_count: %d\n", tr->deleted_obj_count); + ccprintf("deimiter_count: %d\n", tr->delimiter_count); + ccprintf("unexpected_count: %d\n", tr->unexpected_count); + ccprintf("valid_data_size: %d\n", tr->valid_data_size); + ccprintf("erased_data_size: %d\n\n", tr->erased_data_size); +} + +static void wipe_out_nvmem_cache(void) +{ + memset(nvmem_cache_base(NVMEM_TPM), 0, nvmem_user_sizes[NVMEM_TPM]); +} + +static int prepare_nvmem_contents(void) +{ + struct nvmem_tag *tag; + + memcpy(write_buffer, legacy_nvmem_image, sizeof(write_buffer)); + tag = (struct nvmem_tag *)write_buffer; + + app_compute_hash(tag->padding, NVMEM_PARTITION_SIZE - NVMEM_SHA_SIZE, + tag->sha, sizeof(tag->sha)); + app_cipher(tag->sha, tag + 1, tag + 1, + NVMEM_PARTITION_SIZE - sizeof(struct nvmem_tag)); + + return flash_physical_write(CONFIG_FLASH_NVMEM_BASE_A - + CONFIG_PROGRAM_MEMORY_BASE, + sizeof(write_buffer), write_buffer); +} + +static int iterate_over_flash(void) { - int m, n, limit; - uint32_t r_data; + enum ec_error_list rv; + struct nn_container *ch; + struct access_tracker at = {}; + uint8_t buf[CONFIG_FLASH_BANK_SIZE]; + + memset(&test_result, 0, sizeof(test_result)); + ch = (struct nn_container *)buf; + + while ((rv = get_next_object(&at, ch, 1)) == EC_SUCCESS) + switch (ch->container_type) { + case NN_OBJ_OLD_COPY: + if (ch->container_type_copy == NN_OBJ_TRANSACTION_DEL) { + test_result.delimiter_count++; + } else { + test_result.deleted_obj_count++; + test_result.erased_data_size += ch->size; + } + break; + + case NN_OBJ_TUPLE: + test_result.var_count++; + test_result.valid_data_size += ch->size; + break; + + case NN_OBJ_TPM_RESERVED: + test_result.reserved_obj_count++; + test_result.valid_data_size += ch->size; + break; + + case NN_OBJ_TPM_EVICTABLE: + test_result.evictable_obj_count++; + test_result.valid_data_size += ch->size; + break; + + case NN_OBJ_TRANSACTION_DEL: + test_result.delimiter_count++; + break; + default: + test_result.unexpected_count++; + break; + } - /* Ensure it will fit in the write buffer */ - TEST_ASSERT((num_bytes + offset) <= NVMEM_PARTITION_SIZE); - /* Seed random number sequence */ - r_data = prng((uint32_t)clock()); - m = 0; - while (m < num_bytes) { - r_data = prng(r_data); - limit = MIN(4, num_bytes - m); - /* No byte alignment assumptions */ - for (n = 0; n < limit; n++) - write_buffer[offset + m + n] = (r_data >> (n*8)) & 0xff; - m += limit; + if (rv != EC_ERROR_MEMORY_ALLOCATION) { + ccprintf("\n%s:%d - unexpected return value %d\n", __func__, + __LINE__, rv); + return rv; } - return EC_SUCCESS; + /* Verify that there is a delimiter at the top of the flash. */ + if (at.mt.data_offset > sizeof(*at.mt.ph)) { + if ((at.mt.ph == at.dt.ph) && + (((at.mt.data_offset - sizeof(struct nn_container))) == + at.dt.data_offset)) { + return EC_SUCCESS; + } + } else { + if ((at.dt.ph == list_element_to_ph(at.list_index)) && + (at.dt.data_offset == + (CONFIG_FLASH_BANK_SIZE - sizeof(struct nn_container)))) { + ccprintf("%s:%d edge delimiter case OK\n", __func__, + __LINE__); + return EC_SUCCESS; + } + } + ccprintf("%s:%d bad delimiter location: ph %p, " + "dt.ph %p, offset %d, delim offset %d\n", + __func__, __LINE__, at.mt.ph, at.dt.ph, at.mt.data_offset, + at.dt.data_offset); + + return EC_ERROR_INVAL; } -static int test_write_read(uint32_t offset, uint32_t num_bytes, int user) +static void *page_to_flash_addr(int page_num) { - int ret; + uint32_t base_offset = CONFIG_FLASH_NEW_NVMEM_BASE_A; - /* Generate source data */ - generate_random_data(0, num_bytes); - /* Write source data to NvMem */ - ret = nvmem_write(offset, num_bytes, write_buffer, user); - /* Write to flash */ - ret = nvmem_commit(); - if (ret != EC_SUCCESS) - return ret; - /* Read from flash */ - nvmem_read(offset, num_bytes, read_buffer, user); - /* Verify that write to flash was successful */ - TEST_ASSERT_ARRAY_EQ(write_buffer, read_buffer, num_bytes); + if (page_num > NEW_NVMEM_TOTAL_PAGES) + return NULL; - return EC_SUCCESS; + if (page_num >= (NEW_NVMEM_TOTAL_PAGES / 2)) { + page_num -= (NEW_NVMEM_TOTAL_PAGES / 2); + base_offset = CONFIG_FLASH_NEW_NVMEM_BASE_B; + } + + return (void *)((uintptr_t)base_offset + + page_num * CONFIG_FLASH_BANK_SIZE); } -static int write_full_buffer(uint32_t size, int user) +static int post_init_from_scratch(uint8_t flash_value) { - uint32_t offset; - uint32_t len; - int ret; + int i; + void *flash_p; + + memset(write_buffer, flash_value, sizeof(write_buffer)); + + /* Overwrite nvmem flash space with junk value. */ + flash_physical_write( + CONFIG_FLASH_NEW_NVMEM_BASE_A - CONFIG_PROGRAM_MEMORY_BASE, + NEW_FLASH_HALF_NVMEM_SIZE, (const char *)write_buffer); + flash_physical_write( + CONFIG_FLASH_NEW_NVMEM_BASE_B - CONFIG_PROGRAM_MEMORY_BASE, + NEW_FLASH_HALF_NVMEM_SIZE, (const char *)write_buffer); + + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + TEST_ASSERT(test_result.var_count == 0); + TEST_ASSERT(test_result.reserved_obj_count == 38); + TEST_ASSERT(test_result.evictable_obj_count == 0); + TEST_ASSERT(test_result.deleted_obj_count == 0); + TEST_ASSERT(test_result.unexpected_count == 0); + TEST_ASSERT(test_result.valid_data_size == 1088); + TEST_ASSERT(total_var_space == 0); + + for (i = 0; i < (NEW_NVMEM_TOTAL_PAGES - 1); i++) { + flash_p = page_to_flash_addr(i); + + TEST_ASSERT(!!flash_p); + TEST_ASSERT(is_uninitialized(flash_p, CONFIG_FLASH_BANK_SIZE)); + } - /* Start at beginning of the user buffer */ - offset = 0; - do { - /* User default segment length unless it will exceed */ - len = MIN(WRITE_SEGMENT_LEN, size - offset); - /* Generate data for tx buffer */ - generate_random_data(offset, len); - /* Write data to Nvmem cache memory */ - nvmem_write(offset, len, &write_buffer[offset], user); - /* Write to flash */ - ret = nvmem_commit(); - if (ret != EC_SUCCESS) - return ret; - /* Adjust starting offset by segment length */ - offset += len; - } while (offset < size); - - /* Entire flash buffer should be full at this point */ - nvmem_read(0, size, read_buffer, user); - /* Verify that write to flash was successful */ - TEST_ASSERT_ARRAY_EQ(write_buffer, read_buffer, size); + flash_p = page_to_flash_addr(i); + TEST_ASSERT(!is_uninitialized(flash_p, CONFIG_FLASH_BANK_SIZE)); return EC_SUCCESS; } +/* + * The purpose of this test is to check NvMem initialization when NvMem is + * completely erased (i.e. following SpiFlash write of program). In this case, + * nvmem_init() is expected to create initial flash storage containing + * reserved objects only. + */ static int test_fully_erased_nvmem(void) { - /* - * The purpose of this test is to check NvMem intialization when NvMem - * is completely erased (i.e. following SpiFlash write of program). In - * this configuration, nvmem_init() should be able to detect this case - * and configure an initial NvMem partition. - */ - /* Erase full NvMem area */ - flash_physical_erase(CONFIG_FLASH_NVMEM_OFFSET_A, - NVMEM_PARTITION_SIZE); - flash_physical_erase(CONFIG_FLASH_NVMEM_OFFSET_B, - NVMEM_PARTITION_SIZE); - /* Call NvMem initialization function */ - return nvmem_init(); + return post_init_from_scratch(0xff); } -static int test_configured_nvmem(void) +/* + * The purpose of this test is to check nvmem_init() in the case when no valid + * pages exist but flash space is garbled as opposed to be fully erased. In + * this case, the initialization is expected to create one new valid page and + * erase the rest of the pages. + */ +static int test_corrupt_nvmem(void) { - /* - * The purpose of this test is to check nvmem_init() when both - * partitions are configured and valid. - */ + return post_init_from_scratch(0x55); +} - /* Call NvMem initialization */ - return nvmem_init(); +static int prepare_new_flash(void) +{ + TEST_ASSERT(test_fully_erased_nvmem() == EC_SUCCESS); + + /* Now copy sensible information into the nvmem cache. */ + memcpy(nvmem_cache_base(NVMEM_TPM), + legacy_nvmem_image + sizeof(struct nvmem_tag), + nvmem_user_sizes[NVMEM_TPM]); + + dump_nvmem_state("after first save", &test_result); + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + + TEST_ASSERT(test_result.deleted_obj_count == 24); + TEST_ASSERT(test_result.var_count == 0); + TEST_ASSERT(test_result.reserved_obj_count == 40); + TEST_ASSERT(test_result.evictable_obj_count == 9); + TEST_ASSERT(test_result.unexpected_count == 0); + TEST_ASSERT(test_result.valid_data_size == 5128); + TEST_ASSERT(test_result.erased_data_size == 698); + + return EC_SUCCESS; } -/* Verify that nvmem_erase_user_data only erases the given user's data. */ -static int test_nvmem_erase_user_data(void) +static int test_nvmem_save(void) { - uint32_t write_value; - uint32_t read_value; - int i; + const char *key = "var1"; + const char *value = "value of var 1"; + size_t total_var_size; + struct nvmem_test_result old_result; - nvmem_init(); - - /* Make sure all partitions have data in them. */ - for (i = 0; i < NVMEM_NUM_PARTITIONS; i++) { - write_value = i; - nvmem_write(0, sizeof(write_value), &write_value, NVMEM_USER_0); - write_value = 2; - nvmem_write(0, sizeof(write_value), &write_value, NVMEM_USER_1); - write_value = 3; - nvmem_write(0, sizeof(write_value), &write_value, NVMEM_USER_2); - nvmem_commit(); - } + TEST_ASSERT(prepare_new_flash() == EC_SUCCESS); - /* Check that the writes took place. */ - read_value = ~write_value; - nvmem_read(0, sizeof(read_value), &read_value, NVMEM_USER_0); - TEST_ASSERT(read_value == i-1); - nvmem_read(0, sizeof(read_value), &read_value, NVMEM_USER_1); - TEST_ASSERT(read_value == 2); - nvmem_read(0, sizeof(read_value), &read_value, NVMEM_USER_2); - TEST_ASSERT(read_value == 3); + /* + * Verify that saving without changing the cache does not affect flash + * contents. + */ + old_result = test_result; + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); /* - * nvmem_erase_user_data() is supposed to erase the user's data across - * all partitions. + * Save of unmodified cache does not modify the flash contents and + * does not set the delimiter. */ - nvmem_erase_user_data(NVMEM_USER_0); - for (i = 0; i < NVMEM_NUM_PARTITIONS; i++) { - /* Make sure USER 0's data is (still) gone. */ - nvmem_read(0, sizeof(read_value), &read_value, NVMEM_USER_0); - TEST_ASSERT(read_value == 0xffffffff); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + TEST_ASSERT(!memcmp(&test_result, &old_result, sizeof(test_result))); - /* Make sure the other users' data has been untouched. */ - nvmem_read(0, sizeof(read_value), &read_value, NVMEM_USER_1); - TEST_ASSERT(read_value == 2); + wipe_out_nvmem_cache(); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + TEST_ASSERT(!memcmp(&test_result, &old_result, sizeof(test_result))); - /* - * The active partition changes when the contents of the cache - * changes. Therefore, in order to examine all the paritions, - * we'll keep modifying one of the user's data. - */ - nvmem_read(0, sizeof(read_value), &read_value, NVMEM_USER_2); - TEST_ASSERT(read_value == (3+i)); - write_value = 4 + i; - nvmem_write(0, sizeof(write_value), &write_value, NVMEM_USER_2); - nvmem_commit(); - } + /* + * Total size test variable storage takes in flash (container header + * size not included). + */ + total_var_size = strlen(key) + strlen(value) + sizeof(struct tuple); + + /* Verify that we can add a variable to nvmem. */ + TEST_ASSERT(setvar(key, strlen(key), value, strlen(value)) == + EC_SUCCESS); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + + /* Remove changes caused by the new var addition. */ + test_result.var_count -= 1; + test_result.delimiter_count -= 1; + test_result.valid_data_size -= total_var_size; + + TEST_ASSERT(memcmp(&test_result, &old_result, sizeof(test_result)) == + 0); + + /* Verify that we can delete a variable from nvmem. */ + TEST_ASSERT(setvar(key, strlen(key), NULL, 0) == EC_SUCCESS); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + test_result.deleted_obj_count -= 1; + test_result.erased_data_size -= total_var_size; + test_result.delimiter_count -= 1; + TEST_ASSERT(memcmp(&test_result, &old_result, sizeof(test_result)) == + 0); return EC_SUCCESS; } -static int test_corrupt_nvmem(void) +static size_t get_free_nvmem_room(void) { - uint8_t invalid_value = 0x55; - int ret; - struct nvmem_tag *p_part; - uint8_t *p_data; + size_t free_room; + size_t free_pages; + /* Compaction kicks in when 3 pages or less are left. */ + const size_t max_pages = NEW_NVMEM_TOTAL_PAGES - 3; + + ccprintf("list index %d, data offset 0x%x\n", master_at.list_index, + master_at.mt.data_offset); + + if (master_at.list_index >= max_pages) + return 0; + + free_pages = max_pages - master_at.list_index; + free_room = (free_pages - 1) * (CONFIG_FLASH_BANK_SIZE - + sizeof(struct nn_page_header)) + + CONFIG_FLASH_BANK_SIZE - master_at.mt.data_offset; + ccprintf("free pages %d, data offset 0x%x\n", free_pages, + master_at.mt.data_offset); + return free_room; +} + +static int test_nvmem_compaction(void) +{ + char value[100]; /* Definitely more than enough. */ + const char *key = "var 1"; + int i; + size_t key_len; + size_t val_len; + size_t free_room; + size_t real_var_size; + size_t var_space; + int max_vars; + int erased_data_size; + const size_t alignment_mask = CONFIG_FLASH_WRITE_SIZE - 1; + + key_len = strlen(key); + val_len = snprintf(value, sizeof(value), "variable value is %04d", 0); + + TEST_ASSERT(prepare_new_flash() == EC_SUCCESS); /* - * The purpose of this test is to check nvmem_init() in the case when no - * vailid partition exists (not fully erased and no valid sha). In this - * case, the initialization create one new valid partition. + * Remember how much room was erased before flooding nvmem with erased + * values. */ + erased_data_size = test_result.erased_data_size; - /* Overwrite each partition will all 0s */ - memset(write_buffer, invalid_value, NVMEM_PARTITION_SIZE); - flash_physical_write(CONFIG_FLASH_NVMEM_OFFSET_A, - NVMEM_PARTITION_SIZE, - (const char *)write_buffer); - flash_physical_write(CONFIG_FLASH_NVMEM_OFFSET_B, - NVMEM_PARTITION_SIZE, - (const char *)write_buffer); + /* Let's see how much free room there is. */ + free_room = get_free_nvmem_room(); + TEST_ASSERT(free_room); + + /* How much room (key, value) pair takes in a container. */ + real_var_size = val_len + key_len + sizeof(struct tuple); /* - * The initialization function will look for a valid partition and if - * none is found, it will create one, and save it at partition index - * 1. + * See how many vars including containers should be able to fit there. + * + * First calculate rounded up space a var will take. Apart from the + * var itself there will be a container header and a delimiter. */ - ret = nvmem_init(); - if (ret) - return ret; + var_space = (real_var_size + 2 * sizeof(struct nn_container) + + alignment_mask) & ~alignment_mask; + + max_vars = free_room / var_space; /* - * nvmem_init() called on uninitialized flash will create the first - * valid partition with generation set to 0 at flash partition 1. - * - * Check here that partition 1 has a generation number of 0. + * And now flood the NVMEM with erased values (each new setvar() + * invocation erases the previous instance. */ - p_part = (struct nvmem_tag *)CONFIG_FLASH_NVMEM_BASE_B; - TEST_ASSERT(p_part->generation == 0); - p_data = (uint8_t *)p_part + sizeof(struct nvmem_tag); + for (i = 0; i <= max_vars; i++) { + snprintf(value, sizeof(value), "variable value is %04d", i); + TEST_ASSERT(setvar(key, key_len, value, val_len) == EC_SUCCESS); + } - /* Verify that partition 0 is still empty. */ - memset(write_buffer, invalid_value, NVMEM_PARTITION_SIZE); - p_data = (void *)CONFIG_FLASH_NVMEM_BASE_A; - TEST_ASSERT_ARRAY_EQ(write_buffer, p_data, NVMEM_PARTITION_SIZE); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + /* Make sure there was no compaction yet. */ + TEST_ASSERT(test_result.erased_data_size > erased_data_size); - /* Now let's write a different value into user NVMEM_CR50 */ - invalid_value ^= ~0; - TEST_ASSERT(nvmem_write(0, sizeof(invalid_value), - &invalid_value, NVMEM_USER_0) == EC_SUCCESS); - TEST_ASSERT(nvmem_commit() == EC_SUCCESS); + /* This is how much the erased space grew as a result of flooding. */ + erased_data_size = test_result.erased_data_size - erased_data_size; + TEST_ASSERT(erased_data_size == max_vars * real_var_size); - /* Verify that partition 1 generation did not change. */ - TEST_ASSERT(p_part->generation == 0); + /* This will take it over the compaction limit. */ + val_len = snprintf(value, sizeof(value), "variable value is %03d", i); + TEST_ASSERT(setvar(key, key_len, value, val_len) == EC_SUCCESS); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + TEST_ASSERT(test_result.erased_data_size < var_space); + return EC_SUCCESS; +} + +static int test_configured_nvmem(void) +{ /* - * Now verify that partition 0 generation is set to 1; + * The purpose of this test is to check how nvmem_init() initializes + * from previously saved flash contents. */ - p_part = (struct nvmem_tag *)CONFIG_FLASH_NVMEM_BASE_A; - TEST_ASSERT(p_part->generation == 1); + TEST_ASSERT(prepare_nvmem_contents() == EC_SUCCESS); - return EC_SUCCESS; + /* + * This is initialization from legacy flash contents which replaces + * legacy flash image with the new format flash image + */ + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + + /* And this is initialization from the new flash layout. */ + return nvmem_init(); } -static int test_write_read_sequence(void) +static uint8_t find_lb(const void *data) { - uint32_t offset; - uint32_t length; - int user; - int n; - int ret; - - for (user = 0; user < NVMEM_NUM_USERS; user++) { - /* Length for each write/read segment */ - length = nvmem_user_sizes[user] / WRITE_READ_SEGMENTS; - /* Start at beginning of user buffer */ - offset = 0; - for (n = 0; n < WRITE_READ_SEGMENTS; n++) { - ret = test_write_read(offset, length, user); - if (ret != EC_SUCCESS) - return ret; - /* Adjust offset by segment length */ - offset += length; - /* For 1st iteration only, adjust to create stagger */ - if (n == 0) - offset -= length / 2; - - } - } - return EC_SUCCESS; + return (const uint8_t *)memchr(data, '#', 256) - (const uint8_t *)data; } -static int test_write_full_multi(void) +/* + * Helper function, depending on the argument value either writes variables + * into nvmem and verifies their presence, or deletes them and verifies that + * they indeed disappear. + */ +static int var_read_write_delete_helper(int do_write) { - int n; - int ret; + size_t i; + uint16_t saved_total_var_space; + uint32_t coverage_map; + + const struct { + uint8_t *key; + uint8_t *value; + } kv_pairs[] = { + /* Use # as the delimiter to allow \0 in keys/values. */ + {"\0key\00#", "value of key2#"}, {"key1#", "value of key1#"}, + {"key2#", "value of key2#"}, {"key3#", "value of\0 key3#"}, + {"ke\04#", "value\0 of\0 key4#"}, + }; + + coverage_map = 0; + saved_total_var_space = total_var_space; /* - * The purpose of this test is to completely fill each user buffer in - * NvMem with random data a segment length at a time. The data written - * to NvMem is saved in write_buffer[] and then can be used to check the - * NvMem writes were successful by reading and then comparing each user - * buffer. + * Read all vars, one at a time, verifying that they shows up in + * getvar results when appropriate but not before. */ - for (n = 0; n < NVMEM_NUM_USERS; n++) { - ret = write_full_buffer(nvmem_user_sizes[n], n); - if (ret != EC_SUCCESS) - return ret; + for (i = 0; i <= ARRAY_SIZE(kv_pairs); i++) { + size_t j; + uint8_t key_len; + uint8_t val_len; + const void *value; + + for (j = 0; j < ARRAY_SIZE(kv_pairs); j++) { + struct tuple *t; + + coverage_map |= 1; + + key_len = find_lb(kv_pairs[j].key); + t = getvar(kv_pairs[j].key, key_len); + + if ((j >= i) ^ !do_write) { + TEST_ASSERT(t == NULL); + continue; + } + + coverage_map |= 2; + + TEST_ASSERT(saved_total_var_space == total_var_space); + + /* Confirm that what we found is the right variable. */ + val_len = find_lb(kv_pairs[j].value); + + TEST_ASSERT(t->key_len == key_len); + TEST_ASSERT(t->val_len == val_len); + TEST_ASSERT( + !memcmp(kv_pairs[j].key, t->data_, key_len)); + TEST_ASSERT(!memcmp(kv_pairs[j].value, + t->data_ + key_len, val_len)); + freevar(t); + } + + if (i == ARRAY_SIZE(kv_pairs)) { + coverage_map |= 4; + /* All four variables have been processed. */ + break; + } + + val_len = find_lb(kv_pairs[i].value); + key_len = find_lb(kv_pairs[i].key); + value = kv_pairs[i].value; + if (!do_write) { + + coverage_map |= 8; + + saved_total_var_space -= val_len + key_len; + /* + * Make sure all val_len == 0 and val == NULL + * combinations are exercised. + */ + switch (i) { + case 0: + val_len = 0; + coverage_map |= 0x10; + break; + + case 1: + coverage_map |= 0x20; + value = NULL; + break; + default: + coverage_map |= 0x40; + val_len = 0; + value = NULL; + break; + } + } else { + coverage_map |= 0x80; + saved_total_var_space += val_len + key_len; + } + key_len = find_lb(kv_pairs[i].key); + TEST_ASSERT(setvar(kv_pairs[i].key, key_len, value, val_len) == + EC_SUCCESS); + + TEST_ASSERT(saved_total_var_space == total_var_space); } + + if (do_write) + TEST_ASSERT(coverage_map == 0x87); + else + TEST_ASSERT(coverage_map == 0x7f); + return EC_SUCCESS; } -static int test_write_fail(void) +static int test_var_read_write_delete(void) { - uint32_t offset = 0; - uint32_t num_bytes = 0x200; - int ret; + TEST_ASSERT(post_init_from_scratch(0xff) == EC_SUCCESS); - /* Do write/read sequence that's expected to be successful */ - if (test_write_read(offset, num_bytes, NVMEM_USER_0)) - return EC_ERROR_UNKNOWN; + ccprintf("\n%s: starting write cycle\n", __func__); + TEST_ASSERT(var_read_write_delete_helper(1) == EC_SUCCESS); - /* Prevent flash erase/write operations */ - flash_write_fail = 1; - /* Attempt flash write */ - ret = test_write_read(offset, num_bytes, NVMEM_USER_0); - /* Resume normal operation */ - flash_write_fail = 0; + ccprintf("%s: starting delete cycle\n", __func__); + TEST_ASSERT(var_read_write_delete_helper(0) == EC_SUCCESS); + + return EC_SUCCESS; +} +/* Verify that nvmem_erase_user_data only erases the given user's data. */ +static int test_nvmem_erase_tpm_data(void) +{ + TEST_ASSERT(prepare_nvmem_contents() == EC_SUCCESS); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + browse_flash_contents(1); + TEST_ASSERT(nvmem_erase_tpm_data() == EC_SUCCESS); + browse_flash_contents(1); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + TEST_ASSERT(test_result.deleted_obj_count == 0); + TEST_ASSERT(test_result.var_count == 3); + TEST_ASSERT(test_result.reserved_obj_count == 0); + TEST_ASSERT(test_result.evictable_obj_count == 0); + TEST_ASSERT(test_result.unexpected_count == 0); + TEST_ASSERT(test_result.valid_data_size == 86); + TEST_ASSERT(test_result.erased_data_size == 0); - /* This test is successful if write attempt failed */ - return !ret; + return EC_SUCCESS; } -static int test_buffer_overflow(void) +static size_t fill_obj_offsets(uint16_t *offsets, size_t max_objects) { - int ret; - int n; + size_t i; + size_t obj_count; - /* - * The purpose of this test is to check that NvMem writes behave - * properly in relation to the defined length of each user buffer. A - * write operation to completely fill the buffer is done first. This - * should pass. Then the same buffer is written to with one extra byte - * and this operation is expected to fail. - */ + obj_count = init_object_offsets(offsets, max_objects); - /* Do test for each user buffer */ - for (n = 0; n < NVMEM_NUM_USERS; n++) { - /* Write full buffer */ - ret = write_full_buffer(nvmem_user_sizes[n], n); - if (ret != EC_SUCCESS) - return ret; - /* Attempt to write full buffer plus 1 extra byte */ - ret = write_full_buffer(nvmem_user_sizes[n] + 1, n); - if (!ret) - return EC_ERROR_UNKNOWN; + ccprintf("%d objects\n", obj_count); + for (i = 0; i < obj_count; i++) { + uint32_t *op; + + op = evictable_offs_to_addr(offsets[i]); + ccprintf("offs %04x:%08x:%08x:%08x addr %p size %d\n", + offsets[i], op[-1], op[0], op[1], op, + (uintptr_t)nvmem_cache_base(NVMEM_TPM) + op[-1] - + (uintptr_t)op); } - /* Test case where user buffer number is valid */ - ret = test_write_read(0, 0x100, NVMEM_USER_0); - if (ret != EC_SUCCESS) - return ret; - /* Attempt same write, but with invalid user number */ - ret = test_write_read(0, 0x100, NVMEM_NUM_USERS); - if (!ret) - return ret; + return obj_count; +} - return EC_SUCCESS; +static size_t fill_cache_offsets(const void *cache, uint16_t *offsets, + size_t max_objects) +{ + uint8_t buf[nvmem_user_sizes[NVMEM_TPM]]; + void *real_cache; + size_t num_offsets; + + real_cache = nvmem_cache_base(NVMEM_TPM); + memcpy(buf, real_cache, sizeof(buf)); + + memcpy(real_cache, cache, sizeof(buf)); + memset(offsets, 0, sizeof(*offsets) * max_objects); + num_offsets = fill_obj_offsets(offsets, max_objects); + + /* Restore the real cache. */ + memcpy(real_cache, buf, sizeof(buf)); + + return num_offsets; } +#define MAX_OFFSETS 20 -static int test_move(void) +static uint32_t get_evict_size(const uint8_t *cache, uint16_t offset) { - uint32_t len = 0x100; - uint32_t nv1_offset; - uint32_t nv2_offset; - int user = 0; - int n; - int ret; + uint32_t next_addr; + uint32_t cache_offset; - /* - * The purpose of this test is to check that nvmem_move() behaves - * properly. This test only uses one user buffer as accessing multiple - * user buffers is tested separately. This test uses writes a set of - * test data then test move operations with full overlap, half overlap - * and no overlap. Folliwng these tests, the boundary conditions for - * move operations are checked for the giver user buffer. - */ + cache_offset = s_evictNvStart + offset; + memcpy(&next_addr, cache + cache_offset - sizeof(next_addr), + sizeof(next_addr)); + + return next_addr - cache_offset; +} + +/* Returns zero if the two objects are identical. */ +static int compare_objects(const uint8_t *cache1, uint16_t offset1, + const uint8_t *cache2, uint16_t offset2) +{ + uint32_t size1; + uint32_t size2; + + size1 = get_evict_size(cache1, offset1); + size2 = get_evict_size(cache2, offset2); + + if (size1 == size2) + return memcmp(cache1 + s_evictNvStart + offset1, + cache2 + s_evictNvStart + offset2, size1); + + return 1; +} +/* + * Compare two instances of NVMEM caches. Reserved spaces should be exactly + * the same for the match, but evictable objects could be rearranged due to + * compaction, updating, etc. + * + * For the two cache instances to be considered the same the sets and contents + * of the evictable object spaces must also match object to object. + */ +static int caches_match(const uint8_t *cache1, const uint8_t *cache2) +{ + int failed_count; + size_t cache1_offs_count; + size_t cache2_offs_count; + size_t i; + uint16_t cache1_offsets[MAX_OFFSETS]; + uint16_t cache2_offsets[MAX_OFFSETS]; + + for (failed_count = i = 0; i < NV_PSEUDO_RESERVE_LAST; i++) { + NV_RESERVED_ITEM ri; + struct { + uint32_t offset; + uint32_t size; + } ranges[3]; + size_t j; + + NvGetReserved(i, &ri); + + ranges[0].offset = ri.offset; + + if (i != NV_STATE_CLEAR) { + ranges[0].size = ri.size; + ranges[1].size = 0; + } else { + ranges[0].size = offsetof(STATE_CLEAR_DATA, pcrSave); + ranges[1].offset = ranges[0].offset + ranges[0].size; + ranges[1].size = sizeof(PCR_SAVE); + ranges[2].offset = ranges[1].offset + ranges[1].size; + ranges[2].size = sizeof(PCR_AUTHVALUE); + } + + for (j = 0; j < ARRAY_SIZE(ranges); j++) { + + uint32_t offset; + uint32_t size; + uint32_t k; + + size = ranges[j].size; + if (!size) + break; + + offset = ranges[j].offset; - nv1_offset = 0; - for (n = 0; n < 3; n++) { - /* Generate Test data */ - generate_random_data(nv1_offset, len); - nv2_offset = nv1_offset + (len / 2) * n; - /* Write data to Nvmem cache memory */ - nvmem_write(nv1_offset, len, &write_buffer[nv1_offset], user); - nvmem_commit(); - /* Test move while data is in cache area */ - nvmem_move(nv1_offset, nv2_offset, len, user); - nvmem_read(nv2_offset, len, read_buffer, user); - if (memcmp(write_buffer, read_buffer, len)) - return EC_ERROR_UNKNOWN; - ccprintf("Memmove nv1 = 0x%x, nv2 = 0x%x\n", - nv1_offset, nv2_offset); + if (!memcmp(cache1 + offset, cache2 + offset, size)) + continue; + + ccprintf("%s:%d failed comparing %d:%d:\n", __func__, + __LINE__, i, j); + for (k = offset; k < (offset + size); k++) + if (cache1[k] != cache2[k]) + ccprintf(" %3d:%02x", k - offset, + cache1[k]); + ccprintf("\n"); + for (k = offset; k < (offset + size); k++) + if (cache1[k] != cache2[k]) + ccprintf(" %3d:%02x", k - offset, + cache2[k]); + ccprintf("\n"); + + failed_count++; + } } - /* Test invalid buffer offsets */ - /* Destination offset is equal to length of buffer */ - nv1_offset = 0; - nv2_offset = nvmem_user_sizes[user]; - /* Attempt to move just 1 byte */ - ret = nvmem_move(nv1_offset, nv2_offset, 1, user); - if (!ret) - return EC_ERROR_UNKNOWN; - - /* Source offset is equal to length of buffer */ - nv1_offset = nvmem_user_sizes[user]; - nv2_offset = 0; - /* Attempt to move just 1 byte */ - ret = nvmem_move(nv1_offset, nv2_offset, 1, user); - if (!ret) - return EC_ERROR_UNKNOWN; - - nv1_offset = 0; - nv2_offset = nvmem_user_sizes[user] - len; - /* Move data chunk from start to end of buffer */ - ret = nvmem_move(nv1_offset, nv2_offset, - len, user); - if (ret) - return ret; - - /* Attempt to move data chunk 1 byte beyond end of user buffer */ - nv1_offset = 0; - nv2_offset = nvmem_user_sizes[user] - len + 1; - ret = nvmem_move(nv1_offset, nv2_offset, - len, user); - if (!ret) - return EC_ERROR_UNKNOWN; - /* nvmem_move returned an error, need to clear internal error state */ - nvmem_commit(); + TEST_ASSERT(!failed_count); + + cache1_offs_count = fill_cache_offsets(cache1, cache1_offsets, + ARRAY_SIZE(cache1_offsets)); + cache2_offs_count = fill_cache_offsets(cache2, cache2_offsets, + ARRAY_SIZE(cache2_offsets)); + + TEST_ASSERT(cache1_offs_count == cache2_offs_count); + + for (i = 0; (i < ARRAY_SIZE(cache1_offsets)) && cache2_offs_count; + i++) { + size_t j; + + for (j = 0; j < cache2_offs_count; j++) { + if (compare_objects(cache1, cache1_offsets[i], cache2, + cache2_offsets[j])) + continue; + /* Remove object from the cache2 offsets. */ + cache2_offsets[j] = cache2_offsets[--cache2_offs_count]; + break; + } + } + + TEST_ASSERT(cache2_offs_count == 0); return EC_SUCCESS; } -static int test_is_different(void) +static int prepare_post_migration_nvmem(void) { - uint32_t len = 0x41; - uint32_t nv1_offset = 0; - int user = 1; - int ret; + TEST_ASSERT(prepare_nvmem_contents() == EC_SUCCESS); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + return EC_SUCCESS; +} +/* + * This test creates various failure conditions related to interrupted nvmem + * save operations and verifies that transaction integrity is maintained - + * i.e. either all variables get updated, + */ +static int test_nvmem_incomplete_transaction(void) +{ /* - * The purpose of this test is to verify nv_is_different(). Test data is - * written to a location in user buffer 1, then a case that's expected - * to pass along with a case that is expected to fail are checked. Next - * the same tests are repeated when the NvMem write is followed by a - * commit operation. + * Will be more than enough, we can't store more than 15 objects or so + * anyways. */ + uint16_t offsets[MAX_OFFSETS]; + size_t num_objects; + uint8_t buf[nvmem_user_sizes[NVMEM_TPM]]; + + TEST_ASSERT(prepare_post_migration_nvmem() == EC_SUCCESS); + num_objects = fill_obj_offsets(offsets, ARRAY_SIZE(offsets)); + TEST_ASSERT(num_objects == 9); + + /* Save cache state before deleting objects. */ + memcpy(buf, nvmem_cache_base(NVMEM_TPM), sizeof(buf)); + + drop_evictable_obj(evictable_offs_to_addr(offsets[4])); + drop_evictable_obj(evictable_offs_to_addr(offsets[3])); + + failure_mode = TEST_FAIL_WHEN_SAVING; + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + wipe_out_nvmem_cache(); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + + TEST_ASSERT(caches_match(buf, nvmem_cache_base(NVMEM_TPM)) == + EC_SUCCESS); + drop_evictable_obj(evictable_offs_to_addr(offsets[4])); + drop_evictable_obj(evictable_offs_to_addr(offsets[3])); + + /* Check if failure when invalidating is recovered after restart. */ + failure_mode = TEST_FAIL_WHEN_INVALIDATING; + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + ccprintf("%s:%d\n", __func__, __LINE__); + wipe_out_nvmem_cache(); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + ccprintf("%s:%d\n", __func__, __LINE__); + num_objects = fill_obj_offsets(offsets, ARRAY_SIZE(offsets)); + TEST_ASSERT(num_objects == 7); - /* Generate test data */ - generate_random_data(nv1_offset, len); - /* Write to NvMem cache buffer */ - nvmem_write(nv1_offset, len, &write_buffer[nv1_offset], user); - /* Expected to be the same */ - ret = nvmem_is_different(nv1_offset, len, - &write_buffer[nv1_offset], user); - if (ret) - return EC_ERROR_UNKNOWN; - - /* Expected to be different */ - ret = nvmem_is_different(nv1_offset + 1, len, - &write_buffer[nv1_offset], user); - if (!ret) - return EC_ERROR_UNKNOWN; - - /* Commit cache buffer and retest */ - nvmem_commit(); - /* Expected to be the same */ - ret = nvmem_is_different(nv1_offset, len, - &write_buffer[nv1_offset], user); - if (ret) - return EC_ERROR_UNKNOWN; - - /* Expected to be different */ - write_buffer[nv1_offset] ^= 0xff; - ret = nvmem_is_different(nv1_offset, len, - &write_buffer[nv1_offset], user); - if (!ret) - return EC_ERROR_UNKNOWN; + return EC_SUCCESS; +} + +/* + * Verify that interrupted compaction results in a consistent state of the + * NVMEM cache. + */ +static int test_nvmem_interrupted_compaction(void) +{ + uint8_t buf[nvmem_user_sizes[NVMEM_TPM]]; + uint8_t target_list_index; + uint8_t filler = 1; + TEST_ASSERT(prepare_post_migration_nvmem() == EC_SUCCESS); + + /* Let's fill up a couple of pages with erased objects. */ + target_list_index = master_at.list_index + 2; + + do { + /* + * A few randomly picked reserved objects to modify to create + * need for compaction. + */ + const uint8_t objs_to_modify[] = {1, 3, 19, 42}; + size_t i; + + for (i = 0; i < ARRAY_SIZE(objs_to_modify); i++) { + NV_RESERVED_ITEM ri; + + NvGetReserved(i, &ri); + + /* Direct access to the object. */ + memset((uint8_t *)nvmem_cache_base(NVMEM_TPM) + + ri.offset, + filler++, ri.size); + } + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + } while (master_at.list_index != target_list_index); + + /* Save the state of NVMEM cache. */ + memcpy(buf, nvmem_cache_base(NVMEM_TPM), sizeof(buf)); + failure_mode = TEST_FAIL_WHEN_COMPACTING; + compact_nvmem(); + wipe_out_nvmem_cache(); + ccprintf("%s:%d\n", __func__, __LINE__); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + TEST_ASSERT(caches_match(buf, nvmem_cache_base(NVMEM_TPM)) == + EC_SUCCESS); return EC_SUCCESS; } int nvmem_first_task(void *unused) { - uint32_t offset = 0; - uint32_t num_bytes = WRITE_SEGMENT_LEN; - int user = NVMEM_USER_0; - - task_wait_event(0); - /* Generate source data */ - generate_random_data(0, num_bytes); - nvmem_write(0, num_bytes, &write_buffer[offset], user); - /* Read from cache memory */ - nvmem_read(0, num_bytes, read_buffer, user); - /* Verify that write to nvmem was successful */ - TEST_ASSERT_ARRAY_EQ(write_buffer, read_buffer, num_bytes); - /* Wait here with mutex held by this task */ - task_wait_event(0); - /* Write to flash which releases nvmem mutex */ - nvmem_commit(); - nvmem_read(0, num_bytes, read_buffer, user); - /* Verify that write to flash was successful */ - TEST_ASSERT_ARRAY_EQ(write_buffer, read_buffer, num_bytes); - return EC_SUCCESS; } int nvmem_second_task(void *unused) { - uint32_t offset = WRITE_SEGMENT_LEN; - uint32_t num_bytes = WRITE_SEGMENT_LEN; - int user = NVMEM_USER_0; - - task_wait_event(0); - - /* Gen test data and don't overwite test data generated by 1st task */ - generate_random_data(offset, num_bytes); - /* Write test data at offset 0 nvmem user buffer */ - nvmem_write(0, num_bytes, &write_buffer[offset], user); - /* Write to flash */ - nvmem_commit(); - /* Read from nvmem */ - nvmem_read(0, num_bytes, read_buffer, user); - /* Verify that write to nvmem was successful */ - TEST_ASSERT_ARRAY_EQ(&write_buffer[offset], read_buffer, num_bytes); - /* Clear flag to indicate lock test is complete */ - lock_test_started = 0; - return EC_SUCCESS; } -static int test_lock(void) +static void run_test_setup(void) { - /* - * This purpose of this test is to verify the mutex lock portion of the - * nvmem module. There are two additional tasks utilized. The first task - * is woken and it creates some test data and does an - * nvmem_write(). This will cause the mutex to be locked by the 1st - * task. The 1st task then waits and control is returned to this - * function and the 2nd task is woken, the 2nd task also attempts to - * write data to nvmem. The 2nd task should stall waiting for the mutex - * to be unlocked. - * - * When control returns to this function, the 1st task is woken again - * and the nvmem operation is completed. This will allow the 2nd task to - * grab the lock and finish its nvmem operation. The test will not - * complete until the 2nd task finishes the nvmem write. A static global - * flag is used to let this function know when the 2nd task is complete. - * - * Both tasks write to the same location in nvmem so the test will only - * pass if the 2nd task can't write until the nvmem write in the 1st - * task is completed. - */ + /* Allow Flash erase/writes */ + flash_write_fail = 0; + test_reset(); +} - /* Set flag for start of test */ - lock_test_started = 1; - /* Wake first_task */ - task_wake(TASK_ID_NV_1); - task_wait_event(1000); - /* Wake second_task. It should stall waiting for mutex */ - task_wake(TASK_ID_NV_2); - task_wait_event(1000); - /* Go back to first_task so it can complete its nvmem operation */ - task_wake(TASK_ID_NV_1); - /* Wait for 2nd task to complete nvmem operation */ - while (lock_test_started) - task_wait_event(100); +void nvmem_wipe_cache(void) +{ +} - return EC_SUCCESS; +int DCRYPTO_ladder_is_enabled(void) +{ + return 1; } -static int test_nvmem_save(void) +static int test_migration(void) { /* - * The purpose of this test is to verify that if the written value - * did not change the cache contents there is no actual write - * happening at the commit time. + * This purpose of this test is to verify migration of the 'legacy' + * TPM NVMEM format to the new scheme where each element is stored in + * flash in its own container. */ - int dummy_value; - int offset = 0x10; - uint8_t generation_a; - uint8_t generation_b; - uint8_t prev_generation; - uint8_t new_generation; - const struct nvmem_tag *part_a; - const struct nvmem_tag *part_b; - const struct nvmem_tag *new_gen_part; - const struct nvmem_tag *prev_gen_part; - - part_a = (const struct nvmem_tag *)CONFIG_FLASH_NVMEM_BASE_A; - part_b = (const struct nvmem_tag *)CONFIG_FLASH_NVMEM_BASE_B; + TEST_ASSERT(prepare_nvmem_contents() == EC_SUCCESS); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + TEST_ASSERT(iterate_over_flash() == EC_SUCCESS); + TEST_ASSERT(test_result.var_count == 3); + TEST_ASSERT(test_result.reserved_obj_count == 40); + TEST_ASSERT(test_result.evictable_obj_count == 9); + TEST_ASSERT(test_result.delimiter_count == 1); + TEST_ASSERT(test_result.deleted_obj_count == 0); + TEST_ASSERT(test_result.unexpected_count == 0); + TEST_ASSERT(test_result.valid_data_size == 5214); + TEST_ASSERT(total_var_space == 77); + /* Container pointer not yet set. */ + TEST_ASSERT(!master_at.ct.data_offset && !master_at.ct.ph); + return EC_SUCCESS; +} + +/* + * The purpose of this test is to verify variable storage limits, both per + * object and total. + */ +static int test_var_boundaries(void) +{ + const size_t max_size = 255; /* Key and value must fit in a byte. */ + const uint8_t *key; + const uint8_t *val; + size_t key_len; + size_t val_len; + uint16_t saved_total_var_space; + uint32_t coverage_map; + uint8_t var_key[10]; + + TEST_ASSERT(prepare_new_flash() == EC_SUCCESS); + saved_total_var_space = total_var_space; + coverage_map = 0; + /* - * Make sure nvmem is initialized and both partitions have been - * written. + * Let's use the legacy NVMEM image as a source of fairly random but + * reproducible data. */ - nvmem_init(); + key = legacy_nvmem_image; + val = legacy_nvmem_image; /* - * Make sure something is changed at offset 0x10 into the second user - * space. + * Test limit of max variable body space, use keys and values of + * different sizes, below and above the limit. */ - nvmem_read(offset, sizeof(dummy_value), &dummy_value, NVMEM_USER_1); - dummy_value ^= ~0; - nvmem_write(0x10, sizeof(dummy_value), &dummy_value, NVMEM_USER_1); - nvmem_commit(); + for (key_len = 1; key_len < max_size; key_len += 20) { + + coverage_map |= 1; + + val_len = MIN(max_size, MAX_VAR_BODY_SPACE - key_len); + TEST_ASSERT(setvar(key, key_len, val, val_len) == EC_SUCCESS); + TEST_ASSERT(total_var_space == + saved_total_var_space + key_len + val_len); - /* Verify that the two generation values are different. */ - generation_a = part_a->generation; - generation_b = part_b->generation; - TEST_ASSERT(generation_a != generation_b); + /* Now drop the variable from the storage. */ + TEST_ASSERT(setvar(key, key_len, NULL, 0) == EC_SUCCESS); + TEST_ASSERT(total_var_space == saved_total_var_space); + + /* And if key length allows it, try to write too much. */ + if (val_len == max_size) + continue; + + coverage_map |= 2; + /* + * Yes, let's try writing one byte too many and see that the + * attempt is rejected. + */ + val_len++; + TEST_ASSERT(setvar(key, key_len, val, val_len) == + EC_ERROR_INVAL); + TEST_ASSERT(total_var_space == saved_total_var_space); + } /* - * Figure out which one should change next, we are close to the - * beginnig of the test, no wrap is expected. + * Test limit of max total variable space, use keys and values of + * different sizes, below and above the limit. */ - if (generation_a > generation_b) { - prev_generation = generation_a; - new_generation = generation_a + 1; - new_gen_part = part_b; - prev_gen_part = part_a; - } else { - prev_generation = generation_b; - new_generation = generation_b + 1; - new_gen_part = part_a; - prev_gen_part = part_b; + key_len = sizeof(var_key); + val_len = 20; /* Anything below 256 would work. */ + memset(var_key, 'x', key_len); + + while (1) { + int rv; + + /* + * Change the key so that a new variable is added to the + * storage. + */ + rv = setvar(var_key, key_len, val, val_len); + + if (rv == EC_ERROR_OVERFLOW) + break; + + coverage_map |= 4; + TEST_ASSERT(rv == EC_SUCCESS); + var_key[0]++; + saved_total_var_space += key_len + val_len; } - /* Write a new value, this should trigger generation switch. */ - dummy_value += 1; - TEST_ASSERT(nvmem_write(0x10, sizeof(dummy_value), - &dummy_value, NVMEM_USER_1) == EC_SUCCESS); - TEST_ASSERT(nvmem_commit() == EC_SUCCESS); + TEST_ASSERT(saved_total_var_space == total_var_space); + TEST_ASSERT(saved_total_var_space <= MAX_VAR_TOTAL_SPACE); + TEST_ASSERT((saved_total_var_space + key_len + val_len) > + MAX_VAR_TOTAL_SPACE); - TEST_ASSERT(prev_gen_part->generation == prev_generation); - TEST_ASSERT(new_gen_part->generation == new_generation); + TEST_ASSERT(coverage_map == 7); + return EC_SUCCESS; +} - /* Write the same value, this should NOT trigger generation switch. */ - TEST_ASSERT(nvmem_write(0x10, sizeof(dummy_value), - &dummy_value, NVMEM_USER_1) == EC_SUCCESS); - TEST_ASSERT(nvmem_commit() == EC_SUCCESS); +static int verify_ram_index_space(size_t verify_size) +{ + NV_RESERVED_ITEM ri; + size_t i; + uint32_t casted_size; + uint8_t byte; + uint8_t fill_byte = 0x55; + + if (verify_size > RAM_INDEX_SPACE) + return EC_ERROR_INVAL; + + NvGetReserved(NV_RAM_INDEX_SPACE, &ri); + + /* + * Save the size of the index space, needed on machines where size_t + * is a 64 bit value. + */ + casted_size = verify_size; + + /* + * Now write index space in the cache, we write the complete space, + * but on read back only verify_size bytes are expected to be set. + */ + nvmem_write(ri.offset, sizeof(casted_size), &casted_size, NVMEM_TPM); + + for (i = 0; i < RAM_INDEX_SPACE; i++) + nvmem_write(ri.offset + sizeof(casted_size) + i, + sizeof(fill_byte), &fill_byte, NVMEM_TPM); - TEST_ASSERT(prev_gen_part->generation == prev_generation); - TEST_ASSERT(new_gen_part->generation == new_generation); + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + wipe_out_nvmem_cache(); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + + /* Make sure read back size matches. */ + nvmem_read(ri.offset, sizeof(casted_size), &casted_size, NVMEM_TPM); + TEST_ASSERT(casted_size == verify_size); + + /* + * Now check spaces which were supposed to be written (up to + * verify_size) and left intact. + */ + for (i = 0; i < RAM_INDEX_SPACE; i++) { + nvmem_read(ri.offset + sizeof(casted_size) + i, sizeof(byte), + &byte, NVMEM_TPM); + if (i < verify_size) + TEST_ASSERT(byte == fill_byte); + else + TEST_ASSERT(byte == 0); + } return EC_SUCCESS; } -static void run_test_setup(void) +static int test_tpm_nvmem_modify_reserved_objects(void) { - /* Allow Flash erase/writes */ - flash_write_fail = 0; - test_reset(); + NV_RESERVED_ITEM ri; + /* Some random reserved objects' indices. */ + const uint8_t res_obj_ids[] = {1, 4, 9, 20}; + size_t i; + static uint8_t cache_copy[12 * 1024]; + struct nvmem_test_result old_result; + uint64_t new_values[ARRAY_SIZE(res_obj_ids)]; + size_t erased_size; + + TEST_ASSERT(sizeof(cache_copy) >= nvmem_user_sizes[NVMEM_TPM]); + TEST_ASSERT(prepare_new_flash() == EC_SUCCESS); + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + iterate_over_flash(); + old_result = test_result; + + /* Preserve NVMEM cache for future comparison. */ + memcpy(cache_copy, nvmem_cache_base(NVMEM_TPM), + nvmem_user_sizes[NVMEM_TPM]); + + erased_size = 0; + /* Modify several reserved objects in the cache. */ + for (i = 0; i < ARRAY_SIZE(res_obj_ids); i++) { + size_t copy_size; + uint8_t *addr_in_cache; + size_t k; + + NvGetReserved(res_obj_ids[i], &ri); + copy_size = MIN(sizeof(new_values[0]), ri.size); + addr_in_cache = + (uint8_t *)nvmem_cache_base(NVMEM_TPM) + ri.offset; + + /* Prepare a new value for the variable. */ + memcpy(new_values + i, addr_in_cache, copy_size); + for (k = 0; k < copy_size; k++) + ((uint8_t *)(new_values + i))[k] ^= 0x55; + + /* Update value in the cache. */ + memcpy(addr_in_cache, new_values + i, copy_size); + + /* And in the cache copy. */ + memcpy(cache_copy + ri.offset, new_values + i, copy_size); + + /* + * This much will be added to the erased space, object size + * plus index size. + */ + erased_size += ri.size + 1; + } + + /* Save it into flash. */ + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + + /* Wipe out the cache to be sure. */ + wipe_out_nvmem_cache(); + + /* Read NVMEM contents from flash. */ + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + + /* Verify that the cache matches expectations. */ + TEST_ASSERT(!memcmp(cache_copy, nvmem_cache_base(NVMEM_TPM), + nvmem_user_sizes[NVMEM_TPM])); + + iterate_over_flash(); + + /* Update previous results with our expectations. */ + old_result.deleted_obj_count += ARRAY_SIZE(res_obj_ids); + old_result.erased_data_size += erased_size; + old_result.delimiter_count++; + + TEST_ASSERT(!memcmp(&test_result, &old_result, sizeof(test_result))); + + /* Verify several index space cases. */ + for (i = 0; i <= RAM_INDEX_SPACE; i += (RAM_INDEX_SPACE / 2)) + TEST_ASSERT(verify_ram_index_space(i) == EC_SUCCESS); + + return EC_SUCCESS; } -void nvmem_wipe_cache(void) +static int compare_object(uint16_t obj_offset, size_t obj_size, const void *obj) { + uint32_t next_addr; + + memcpy(&next_addr, + evictable_offs_to_addr(obj_offset - sizeof(next_addr)), + sizeof(next_addr)); + + ccprintf("next_addr %x, sum %x size %d\n", next_addr, + (s_evictNvStart + obj_offset + obj_size), obj_size); + TEST_ASSERT(next_addr == (s_evictNvStart + obj_offset + obj_size)); + + if (!memcmp(evictable_offs_to_addr(obj_offset), obj, obj_size)) + return EC_SUCCESS; + + return EC_ERROR_INVAL; } -int DCRYPTO_ladder_is_enabled(void) +static int test_tpm_nvmem_modify_evictable_objects(void) { - return 1; + size_t num_objects; + uint16_t offsets[MAX_OFFSETS]; + uint32_t handles[ARRAY_SIZE(offsets)]; + uint32_t new_evictable_object[30]; + size_t i; + const uint32_t new_obj_handle = 0x100; + static uint8_t modified_obj[CONFIG_FLASH_BANK_SIZE]; + size_t modified_obj_size; + uint32_t modified_obj_handle; + uint32_t deleted_obj_handle; + uint8_t *obj_cache_addr; + size_t num_handles; + int new_obj_index; + int modified_obj_index; + + TEST_ASSERT(prepare_new_flash() == EC_SUCCESS); + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + iterate_over_flash(); + + /* Verify that all evictable objects are there. */ + num_objects = fill_obj_offsets(offsets, ARRAY_SIZE(offsets)); + TEST_ASSERT(num_objects == 9); + num_handles = num_objects; + + /* Save handles of all objects there are. */ + for (i = 0; i < num_objects; i++) { + memcpy(handles + i, evictable_offs_to_addr(offsets[i]), + sizeof(handles[i])); + ccprintf("obj %d handle %08x\n", i, handles[i]); + } + /* + * Let's modify the object which currently is stored second in the + * stack. + */ + modified_obj_size = offsets[3] - offsets[2] - sizeof(uint32_t); + + /* Modify the object and copy modified value into local buffer. */ + obj_cache_addr = evictable_offs_to_addr(offsets[2]); + memcpy(&modified_obj_handle, obj_cache_addr, + sizeof(modified_obj_handle)); + + for (i = 0; i < modified_obj_size; i++) { + uint8_t c; + + c = obj_cache_addr[i]; + + if (i >= sizeof(uint32_t)) { /* Preserve the 4 byte handle. */ + c ^= 0x55; + obj_cache_addr[i] = c; + } + modified_obj[i] = c; + } + + /* Save its handle and then drop the object at offset 5. */ + memcpy(&deleted_obj_handle, evictable_offs_to_addr(offsets[5]), + sizeof(deleted_obj_handle)); + drop_evictable_obj(evictable_offs_to_addr(offsets[5])); + + /* Prepare the new evictable object, first four bytes are the handle. */ + for (i = 0; i < ARRAY_SIZE(new_evictable_object); i++) + new_evictable_object[i] = new_obj_handle + i; + + /* Add it to the cache. */ + add_evictable_obj(new_evictable_object, sizeof(new_evictable_object)); + + /* Save the new cache state in the flash. */ + TEST_ASSERT(new_nvmem_save() == EC_SUCCESS); + + /* Wipe out NVMEM cache just in case. */ + wipe_out_nvmem_cache(); + + /* Read back from flash into cache. */ + TEST_ASSERT(nvmem_init() == EC_SUCCESS); + + /* One object removed, one added, the number should have not changed. */ + TEST_ASSERT(num_objects == + fill_obj_offsets(offsets, ARRAY_SIZE(offsets))); + + new_obj_index = 0; + modified_obj_index = 0; + for (i = 0; i < num_objects; i++) { + uint32_t handle; + size_t j; + + memcpy(&handle, evictable_offs_to_addr(offsets[i]), + sizeof(handles[i])); + ASSERT(handle != deleted_obj_handle); + + if (handle == new_obj_handle) + new_obj_index = i; + else if (handle == modified_obj_handle) + modified_obj_index = i; + /* + * Remove the found handle from the set of handles which were + * there originally. + */ + for (j = 0; j < num_handles; j++) + if (handles[j] == handle) { + num_handles--; + handles[j] = handles[num_handles]; + break; + } + } + + /* + * Removed object's handle is still in the array, and it should be the + * only remaining element. + */ + TEST_ASSERT(num_handles == 1); + TEST_ASSERT(handles[0] == deleted_obj_handle); + TEST_ASSERT(new_obj_index >= 0); /* New handle was seen in the cache. */ + TEST_ASSERT(modified_obj_index >= + 0); /* Modified object was seen in the cache. */ + + TEST_ASSERT(compare_object(offsets[new_obj_index], + sizeof(new_evictable_object), + new_evictable_object) == EC_SUCCESS); + TEST_ASSERT(compare_object(offsets[modified_obj_index], + modified_obj_size, + modified_obj) == EC_SUCCESS); + return EC_SUCCESS; } void run_test(void) { run_test_setup(); + + if (0) { + RUN_TEST(test_nvmem_incomplete_transaction); + test_print_result(); + return; + } + RUN_TEST(test_migration); RUN_TEST(test_corrupt_nvmem); RUN_TEST(test_fully_erased_nvmem); RUN_TEST(test_configured_nvmem); - RUN_TEST(test_write_read_sequence); - RUN_TEST(test_write_full_multi); - RUN_TEST(test_write_fail); - RUN_TEST(test_buffer_overflow); - RUN_TEST(test_move); - RUN_TEST(test_is_different); - RUN_TEST(test_lock); - RUN_TEST(test_nvmem_erase_user_data); RUN_TEST(test_nvmem_save); + RUN_TEST(test_var_read_write_delete); + RUN_TEST(test_nvmem_compaction); + RUN_TEST(test_var_boundaries); + RUN_TEST(test_nvmem_erase_tpm_data); + RUN_TEST(test_tpm_nvmem_modify_reserved_objects); + RUN_TEST(test_tpm_nvmem_modify_evictable_objects); + RUN_TEST(test_nvmem_incomplete_transaction); + failure_mode = TEST_NO_FAILURE; /* In case the above test failed. */ + RUN_TEST(test_nvmem_interrupted_compaction); + failure_mode = TEST_NO_FAILURE; /* In case the above test failed. */ + + /* + * more tests to come + * RUN_TEST(test_lock); + * RUN_TEST(test_malloc_blocking); + */ + test_print_result(); } diff --git a/test/nvmem_test.h b/test/nvmem_test.h new file mode 100644 index 0000000000..f8f166dc5e --- /dev/null +++ b/test/nvmem_test.h @@ -0,0 +1,28 @@ +/* Copyright 2019 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __EC_TEST_NVMEM_TEST_H +#define __EC_TEST_NVMEM_TEST_H + +#define EMBEDDED_MODE 1 +#define NV_C +#include "Global.h" +#undef NV_C +#include "NV_fp.h" +#include "tpm_generated.h" + +enum test_failure_mode { + TEST_NO_FAILURE, + TEST_FAIL_WHEN_SAVING, + TEST_FAIL_WHEN_INVALIDATING, + TEST_FAIL_WHEN_COMPACTING +}; + +extern enum test_failure_mode failure_mode; + +size_t add_evictable_obj(void *obj, size_t obj_size); +void drop_evictable_obj(void *obj); + +#endif /* ! __EC_TEST_NVMEM_TEST_H */ diff --git a/test/nvmem_tpm2_mock.c b/test/nvmem_tpm2_mock.c new file mode 100644 index 0000000000..070525406d --- /dev/null +++ b/test/nvmem_tpm2_mock.c @@ -0,0 +1,377 @@ +/* Copyright 2019 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +/* Stuff from tpm2 directory. */ + +#include "nvmem_test.h" + +#include "console.h" +#include "nvmem.h" +#include "util.h" + +#define NVMEM_CR50_SIZE 272 + +uint32_t s_evictNvStart; +uint32_t s_evictNvEnd; + +/* Calculate size of TPM NVMEM. */ +#define MOCK_NV_MEMORY_SIZE \ + (NVMEM_PARTITION_SIZE - sizeof(struct nvmem_tag) - NVMEM_CR50_SIZE) + +uint32_t nvmem_user_sizes[NVMEM_NUM_USERS] = {MOCK_NV_MEMORY_SIZE, + NVMEM_CR50_SIZE}; + +/* + * Sizes of the reserved objects stored in the TPM NVMEM. Note that the second + * last object is in fact a variable size field starting with 4 bytes of size + * and then up to 512 bytes of actual index data. The array below assumes that + * the full 512 bytes of the index space are used. + */ +const uint16_t res_sizes[] = {4, 2, 2, 2, 66, 66, 66, 66, 66, 66, + 34, 34, 34, 66, 66, 66, 8, 4, 134, 28, + 3, 4, 4, 4, 4, 4, 2, 15, 2, 8, + 4, 4, 4, 96, 2844, 424, 516, 8}; + +static uint16_t res_addrs[ARRAY_SIZE(res_sizes)]; + +BOOL NvEarlyStageFindHandle(TPM_HANDLE handle) +{ + size_t i; + + res_addrs[0] = 0; + + for (i = 1; i < ARRAY_SIZE(res_addrs); i++) + res_addrs[i] = res_addrs[i - 1] + res_sizes[i - 1]; + + s_evictNvStart = res_addrs[i - 1] + res_sizes[i - 1]; + + s_evictNvEnd = MOCK_NV_MEMORY_SIZE; + return 0; +} + +void NvGetReserved(UINT32 index, NV_RESERVED_ITEM *ri) +{ + uint32_t index_size; + + if (index >= ARRAY_SIZE(res_sizes)) { + ri->size = 0; + return; + } + + ri->offset = res_addrs[index]; + if (index != NV_RAM_INDEX_SPACE) { + ri->size = res_sizes[index]; + return; + } + + memcpy(&index_size, nvmem_cache_base(NVMEM_TPM) + ri->offset, + sizeof(index_size)); + + if (index_size == ~0) + /* Must be starting with empty flash memeory. */ + index_size = 0; + + ri->size = index_size + sizeof(index_size); +} + +UINT16 UINT16_Marshal(UINT16 *source, BYTE **buffer, INT32 *size) +{ + uint16_t value; + + if (!size || (*size < sizeof(value))) + return 0; + + value = htobe16(*source); + + memcpy(*buffer, &value, sizeof(value)); + *buffer += sizeof(value); + *size -= sizeof(value); + + return sizeof(value); +} + +UINT16 UINT32_Marshal(UINT32 *source, BYTE **buffer, INT32 *size) +{ + uint32_t value; + + if (!size || (*size < sizeof(value))) + return 0; + + value = htobe32(*source); + + memcpy(*buffer, &value, sizeof(value)); + *buffer += sizeof(value); + *size -= sizeof(value); + + return sizeof(value); +} + +UINT16 UINT64_Marshal(UINT64 *source, BYTE **buffer, INT32 *size) +{ + uint64_t value; + + if (!size || (*size < sizeof(value))) + return 0; + + value = htobe64(*source); + + memcpy(*buffer, &value, sizeof(value)); + *buffer += sizeof(value); + *size -= sizeof(value); + + return sizeof(value); +} + +UINT16 TPM2B_DIGEST_Marshal(TPM2B_DIGEST *source, BYTE **buffer, INT32 *size) +{ + UINT16 total_size; + INT32 i; + uint8_t *p; + + total_size = UINT16_Marshal(&source->t.size, buffer, size); + p = *buffer; + + for (i = 0; (i < source->t.size) && *size; ++i) { + *p++ = source->t.buffer[i]; + *size -= 1; + } + + total_size += i; + *buffer = p; + + return total_size; +} + +uint16_t TPM2B_AUTH_Marshal(TPM2B_AUTH *source, BYTE **buffer, INT32 *size) +{ + return TPM2B_DIGEST_Marshal(source, buffer, size); +} + +uint16_t TPM2B_NONCE_Marshal(TPM2B_AUTH *source, BYTE **buffer, INT32 *size) +{ + return TPM2B_DIGEST_Marshal(source, buffer, size); +} + +TPM_RC UINT16_Unmarshal(UINT16 *target, BYTE **buffer, INT32 *size) +{ + uint16_t value; + + if (!size || *size < sizeof(value)) + return TPM_RC_INSUFFICIENT; + + memcpy(&value, *buffer, sizeof(value)); + *target = be16toh(value); + + *buffer += sizeof(value); + *size -= sizeof(value); + + return TPM_RC_SUCCESS; +} + +TPM_RC UINT32_Unmarshal(UINT32 *target, BYTE **buffer, INT32 *size) +{ + uint32_t value; + + if (!size || *size < sizeof(value)) + return TPM_RC_INSUFFICIENT; + + memcpy(&value, *buffer, sizeof(value)); + *target = be32toh(value); + + *buffer += sizeof(value); + *size -= sizeof(value); + + return TPM_RC_SUCCESS; +} + +TPM_RC UINT64_Unmarshal(UINT64 *target, BYTE **buffer, INT32 *size) +{ + uint64_t value; + + if (!size || *size < sizeof(value)) + return TPM_RC_INSUFFICIENT; + + memcpy(&value, *buffer, sizeof(value)); + *target = be64toh(value); + + *buffer += sizeof(value); + *size -= sizeof(value); + + return TPM_RC_SUCCESS; +} + +TPM_RC TPM2B_DIGEST_Unmarshal(TPM2B_DIGEST *target, BYTE **buffer, INT32 *size) +{ + TPM_RC result; + INT32 i; + uint8_t *p; + + result = UINT16_Unmarshal(&target->t.size, buffer, size); + + if (result != TPM_RC_SUCCESS) + return result; + + if (target->t.size == 0) + return TPM_RC_SUCCESS; + + if ((target->t.size > sizeof(TPMU_HA)) || (target->t.size > *size)) + return TPM_RC_SIZE; + + p = *buffer; + for (i = 0; i < target->t.size; ++i) + target->t.buffer[i] = *p++; + + *buffer = p; + *size -= i; + + return TPM_RC_SUCCESS; +} + +TPM_RC TPM2B_AUTH_Unmarshal(TPM2B_AUTH *target, BYTE **buffer, INT32 *size) +{ + return TPM2B_DIGEST_Unmarshal(target, buffer, size); +} + +TPM_RC TPM2B_NONCE_Unmarshal(TPM2B_AUTH *target, BYTE **buffer, INT32 *size) +{ + return TPM2B_DIGEST_Unmarshal(target, buffer, size); +} + +#define ITER_INIT (~0) + +static void *get_cache_addr(size_t offset) +{ + return (void *)(((uintptr_t)nvmem_cache_base(NVMEM_TPM)) + offset); +} + +static void read_from_cache(size_t offset, size_t size, void *dest) +{ + nvmem_read(offset, size, dest, NVMEM_TPM); +} + +static void write_to_cache(size_t offset, size_t size, void *src) +{ + nvmem_write(offset, size, src, NVMEM_TPM); +} + +/* Copies of the appropriate functions from NV.c in TPM2 library. */ +static uint32_t nv_next(uint32_t *iter) +{ + uint32_t currentIter; + + if (*iter == ITER_INIT) + *iter = s_evictNvStart; + + if ((*iter + sizeof(uint32_t) > s_evictNvEnd) || !*iter) + return 0; + + currentIter = *iter; + read_from_cache(*iter, sizeof(uint32_t), iter); + if (!*iter || (*iter == ITER_INIT)) + return 0; + + return currentIter + sizeof(uint32_t); +} + +static uint32_t nv_get_end(void) +{ + uint32_t iter = ITER_INIT; + uint32_t endAddr = s_evictNvStart; + uint32_t currentAddr; + + while ((currentAddr = nv_next(&iter)) != 0) + endAddr = currentAddr; + + if (endAddr != s_evictNvStart) { + /* Read offset. */ + endAddr -= sizeof(uint32_t); + read_from_cache(endAddr, sizeof(uint32_t), &endAddr); + } + return endAddr; +} + +size_t add_evictable_obj(void *obj, size_t obj_size) +{ + uint32_t end_addr; + uint32_t next_addr; + uint32_t list_end = 0; + + end_addr = nv_get_end(); + + next_addr = end_addr + sizeof(uint32_t) + obj_size; + + if (next_addr >= s_evictNvEnd) { + ccprintf("%s: could not fit %d bytes!\n", __func__, obj_size); + return 0; + } + + /* Write next pointer */ + write_to_cache(end_addr, sizeof(uint32_t), &next_addr); + /* Write entity data. */ + write_to_cache(end_addr + sizeof(uint32_t), obj_size, obj); + + /* Write the end of list if it fits. */ + if (next_addr + sizeof(uint32_t) <= s_evictNvEnd) + write_to_cache(next_addr, sizeof(list_end), &list_end); + + return obj_size; +} + +/* + * It is the responsibility of the caller to pass the proper address of an + * object in the cache. + */ +void drop_evictable_obj(void *obj) +{ + uint32_t next_addr; + uint32_t list_end = 0; + uint32_t obj_addr; + + obj_addr = (uintptr_t)obj - (uintptr_t)nvmem_cache_base(NVMEM_TPM); + read_from_cache(obj_addr - sizeof(next_addr), sizeof(next_addr), + &next_addr); + ccprintf("%s:%d dropping obj at cache addr %x, offset %x, addr %p next " + "addr %x aka %x (off s_evictNvStart)\n", + __func__, __LINE__, obj_addr - s_evictNvStart, obj_addr, obj, + next_addr, next_addr - s_evictNvStart); + + /* + * Now, to make it easier to add objects behind the current one, let's + * pretend there is no more objects. + */ + write_to_cache(obj_addr - sizeof(next_addr), sizeof(list_end), + &list_end); + + if (!next_addr || (next_addr == s_evictNvEnd)) + return; + + /* + * Iterate over objects starting with next_addr, copying them into + * obj_addr. + */ + obj_addr = next_addr; + while (1) { + uint32_t next_next_addr; + uint32_t next_obj_size; + + read_from_cache(next_addr, sizeof(next_next_addr), + &next_next_addr); + + if (!next_next_addr || (next_next_addr == s_evictNvEnd)) + return; + + next_obj_size = next_next_addr - obj_addr - sizeof(uint32_t); + add_evictable_obj( + (void *)((uintptr_t)nvmem_cache_base(NVMEM_TPM) + + next_addr + sizeof(uint32_t)), + next_obj_size); + next_addr = next_next_addr; + obj_addr += next_obj_size + sizeof(next_obj_size); + } +} + +void *evictable_offs_to_addr(uint16_t offset) +{ + return (void *)((uintptr_t)get_cache_addr(s_evictNvStart) + offset); +} diff --git a/test/nvmem_vars.c b/test/nvmem_vars.c deleted file mode 100644 index 99e059215e..0000000000 --- a/test/nvmem_vars.c +++ /dev/null @@ -1,538 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Test of the key=val variable implementation (set, get, delete, etc). - */ - -#include "common.h" -#include "compile_time_macros.h" -#include "nvmem.h" -#include "nvmem_vars.h" -#include "printf.h" -#include "shared_mem.h" -#include "test_util.h" - -/* Declare the user regions (see test_config.h) */ -uint32_t nvmem_user_sizes[] = { - CONFIG_FLASH_NVMEM_VARS_USER_SIZE, -}; -BUILD_ASSERT(ARRAY_SIZE(nvmem_user_sizes) == NVMEM_NUM_USERS); - -/****************************************************************************/ -/* Mock the flash storage */ - -static uint8_t ram_buffer[CONFIG_FLASH_NVMEM_VARS_USER_SIZE]; -static uint8_t flash_buffer[CONFIG_FLASH_NVMEM_VARS_USER_SIZE]; - -extern char *rbuf; - -/* Internal functions exported for test */ -void release_local_copy(void) -{ - rbuf = NULL; -} - -int get_local_copy(void) -{ - if (!rbuf) { - memcpy(ram_buffer, flash_buffer, sizeof(ram_buffer)); - rbuf = (char *)ram_buffer; - } - return EC_SUCCESS; -} - -int nvmem_read(uint32_t startOffset, uint32_t size, - void *data_, enum nvmem_users user) -{ - /* Our mocks make some assumptions */ - if (startOffset != 0 || - size > CONFIG_FLASH_NVMEM_VARS_USER_SIZE || - user != CONFIG_FLASH_NVMEM_VARS_USER_NUM) - return EC_ERROR_UNIMPLEMENTED; - - if (!data_) - return EC_ERROR_INVAL; - - memcpy(data_, flash_buffer, size); - - return EC_SUCCESS; -} - -int nvmem_write(uint32_t startOffset, uint32_t size, - void *data_, enum nvmem_users user) -{ - /* Our mocks make some assumptions */ - if (startOffset != 0 || - size > CONFIG_FLASH_NVMEM_VARS_USER_SIZE || - user != CONFIG_FLASH_NVMEM_VARS_USER_NUM) - return EC_ERROR_UNIMPLEMENTED; - - if (!data_) - return EC_ERROR_INVAL; - - memcpy(ram_buffer, data_, size); - - return EC_SUCCESS; -} - -int nvmem_commit(void) -{ - memcpy(flash_buffer, ram_buffer, CONFIG_FLASH_NVMEM_VARS_USER_SIZE); - return EC_SUCCESS; -} - -int nvmem_erase_user_data(enum nvmem_users user) -{ - memset(ram_buffer, 0xff, sizeof(ram_buffer)); - memset(flash_buffer, 0xff, sizeof(flash_buffer)); - return EC_SUCCESS; -} - -/****************************************************************************/ -/* Helper routines */ - -static void erase_flash(void) -{ - /* Invalidate the RAM cache */ - release_local_copy(); - - /* Zero flash */ - memset(flash_buffer, 0xff, sizeof(flash_buffer)); -} - -/* Erase flash, then copy data_ over it */ -static void load_flash(const uint8_t *data_, size_t data_len) -{ - erase_flash(); - memcpy(flash_buffer, data_, data_len); -} - -/* Return true if flash matches data_, and is followed by 0xff to the end */ -static int verify_flash(const uint8_t *data_, size_t data_len) -{ - size_t i; - - /* mismatch means false */ - if (memcmp(flash_buffer, data_, data_len)) - return 0; - - for (i = data_len; - i < CONFIG_FLASH_NVMEM_VARS_USER_SIZE - data_len; - i++) - if (flash_buffer[i] != 0xff) - return 0; - return 1; -} - -/* - * Treating both as strings, save the pair. - */ -int str_setvar(const char *key, const char *val) -{ - /* Only for tests, so assume the length will fit */ - uint8_t key_len, val_len; - - key_len = strlen(key); - val_len = val ? strlen(val) : 0; - - return setvar(key, key_len, val, val_len); -} - -/* - * Treating both as strings, lookup the key and compare the result with the - * expected value. Return true if they match. - */ -static int str_matches(const char *key, const char *expected_val) -{ - const struct tuple *t = getvar(key, strlen(key)); - uint8_t expected_len; - - if (!expected_val && !t) - return 1; - - if (expected_val && !t) - return 0; - - if (!expected_val && t) - return 0; - - expected_len = strlen(expected_val); - return !memcmp(tuple_val(t), expected_val, expected_len); -} - -/****************************************************************************/ -/* Tests */ - -static int check_init(void) -{ - /* Valid entries */ - const uint8_t good[] = { 0x01, 0x01, 0x00, 'A', 'a', - 0x01, 0x01, 0x00, 'B', 'b', - 0x00 }; - - /* Empty variables are 0x00, followed by all 0xff */ - const uint8_t empty[] = { 0x00 }; - - /* - * This is parsed as though there's only one variable, but it's wrong - * because the rest of the storage isn't 0xff. - */ - const uint8_t bad_key[] = { 0x01, 0x01, 0x00, 'A', 'a', - 0x00, 0x01, 0x00, 'B', 'b', - 0x00 }; - - /* Zero-length variables are not allowed */ - const uint8_t bad_val[] = { 0x01, 0x01, 0x00, 'A', 'a', - 0x01, 0x00, 0x00, 'B', 'b', - 0x00 }; - - /* The next constants use magic numbers based on on the region size */ - BUILD_ASSERT(CONFIG_FLASH_NVMEM_VARS_USER_SIZE == 600); - - /* This is one byte too large */ - const uint8_t too_big[] = { [0] = 0xff, [1] = 0xff, /* 0 - 512 */ - [513] = 0x01, [514] = 0x53, /* 513 - 599 */ - [599] = 0x00 }; - - /* This should just barely fit */ - const uint8_t just_right[] = { [0] = 0xff, [1] = 0xff, /* 0-512 */ - [513] = 0x01, [514] = 0x52, /* 513-598 */ - [599] = 0x00 }; - - /* No end marker */ - const uint8_t not_right[] = { [0] = 0xff, [1] = 0xff, /* 0-512 */ - [513] = 0x01, [514] = 0x52, /* 513-598 */ - [599] = 0xff }; - - load_flash(good, sizeof(good)); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(good, sizeof(good))); - - load_flash(empty, sizeof(empty)); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(empty, sizeof(empty))); - - /* All 0xff quickly runs off the end of the storage */ - erase_flash(); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(empty, sizeof(empty))); - - load_flash(bad_key, sizeof(bad_key)); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(empty, sizeof(empty))); - - load_flash(bad_val, sizeof(bad_val)); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(empty, sizeof(empty))); - - load_flash(too_big, sizeof(too_big)); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(empty, sizeof(empty))); - - load_flash(just_right, sizeof(just_right)); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(just_right, sizeof(just_right))); - - load_flash(not_right, sizeof(not_right)); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(empty, sizeof(empty))); - - return EC_SUCCESS; -} - -static int simple_search(void) -{ - const uint8_t preload[] = { - 0x02, 0x02, 0x00, 'h', 'o', 'y', 'o', - 0x02, 0x4, 0x00, 'y', 'o', 'h', 'o', 'y', 'o', - 0x02, 0x06, 0x00, 'm', 'o', 'y', 'o', 'h', 'o', 'y', 'o', - 0x00 }; - - load_flash(preload, sizeof(preload)); - TEST_ASSERT(initvars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(preload, sizeof(preload))); - - TEST_ASSERT(str_matches("no", 0)); - TEST_ASSERT(str_matches("ho", "yo")); - TEST_ASSERT(str_matches("yo", "hoyo")); - TEST_ASSERT(str_matches("mo", "yohoyo")); - - return EC_SUCCESS; -} - -static int simple_write(void) -{ - const uint8_t after_one[] = { - 0x02, 0x02, 0x00, 'h', 'o', 'y', 'o', - 0x00 }; - - const uint8_t after_two[] = { - 0x02, 0x02, 0x00, 'h', 'o', 'y', 'o', - 0x02, 0x4, 0x00, 'y', 'o', 'h', 'o', 'y', 'o', - 0x00 }; - - const uint8_t after_three[] = { - 0x02, 0x02, 0x00, 'h', 'o', 'y', 'o', - 0x02, 0x4, 0x00, 'y', 'o', 'h', 'o', 'y', 'o', - 0x02, 0x06, 0x00, 'm', 'o', 'y', 'o', 'h', 'o', 'y', 'o', - 0x00 }; - - erase_flash(); - TEST_ASSERT(initvars() == EC_SUCCESS); - - TEST_ASSERT(setvar("ho", 2, "yo", 2) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(after_one, sizeof(after_one))); - - TEST_ASSERT(setvar("yo", 2, "hoyo", 4) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(after_two, sizeof(after_two))); - - TEST_ASSERT(setvar("mo", 2, "yohoyo", 6) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(after_three, sizeof(after_three))); - - return EC_SUCCESS; -} - -static int simple_delete(void) -{ - const char start_with[] = { - 0x01, 0x05, 0x00, 'A', 'a', 'a', 'a', 'a', 'a', - 0x02, 0x03, 0x00, 'B', 'B', 'b', 'b', 'b', - 0x03, 0x06, 0x00, 'C', 'C', 'C', 'x', 'y', 'z', 'p', 'd', 'q', - 0x01, 0x03, 0x00, 'M', 'm', '0', 'm', - 0x04, 0x01, 0x00, 'N', 'N', 'N', 'N', 'n', - 0x00 }; - - const char after_one[] = { - 0x02, 0x03, 0x00, 'B', 'B', 'b', 'b', 'b', - 0x03, 0x06, 0x00, 'C', 'C', 'C', 'x', 'y', 'z', 'p', 'd', 'q', - 0x01, 0x03, 0x00, 'M', 'm', '0', 'm', - 0x04, 0x01, 0x00, 'N', 'N', 'N', 'N', 'n', - 0x00 }; - - const char after_two[] = { - 0x02, 0x03, 0x00, 'B', 'B', 'b', 'b', 'b', - 0x03, 0x06, 0x00, 'C', 'C', 'C', 'x', 'y', 'z', 'p', 'd', 'q', - 0x01, 0x03, 0x00, 'M', 'm', '0', 'm', - 0x00 }; - - const char after_three[] = { - 0x02, 0x03, 0x00, 'B', 'B', 'b', 'b', 'b', - 0x01, 0x03, 0x00, 'M', 'm', '0', 'm', - 0x00 }; - - const char empty[] = { 0x00 }; - - erase_flash(); - TEST_ASSERT(initvars() == EC_SUCCESS); - - TEST_ASSERT(setvar("A", 1, "aaaaa", 5) == EC_SUCCESS); - TEST_ASSERT(setvar("BB", 2, "bbb", 3) == EC_SUCCESS); - TEST_ASSERT(setvar("CCC", 3, "xyzpdq", 6) == EC_SUCCESS); - TEST_ASSERT(setvar("M", 1, "m0m", 3) == EC_SUCCESS); - TEST_ASSERT(setvar("NNNN", 4, "n", 1) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(start_with, sizeof(start_with))); - - /* Zap first variable by setting var_len to 0 */ - TEST_ASSERT(setvar("A", 1, "yohoyo", 0) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(after_one, sizeof(after_one))); - - /* Zap last variable by passing null pointer */ - TEST_ASSERT(setvar("NNNN", 4, 0, 3) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(after_two, sizeof(after_two))); - - /* Ensure that zapping nonexistant variable does nothing */ - TEST_ASSERT(setvar("XXX", 3, 0, 0) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(after_two, sizeof(after_two))); - - /* Zap variable in the middle */ - TEST_ASSERT(setvar("CCC", 3, 0, 0) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(after_three, sizeof(after_three))); - - /* Zap the rest */ - TEST_ASSERT(setvar("BB", 2, 0, 0) == EC_SUCCESS); - TEST_ASSERT(setvar("M", 1, 0, 0) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(empty, sizeof(empty))); - - /* Zapping a nonexistant variable still does nothing */ - TEST_ASSERT(setvar("XXX", 3, 0, 0) == EC_SUCCESS); - TEST_ASSERT(writevars() == EC_SUCCESS); - TEST_ASSERT(verify_flash(empty, sizeof(empty))); - - return EC_SUCCESS; -} - -static int complex_write(void) -{ - erase_flash(); - TEST_ASSERT(initvars() == EC_SUCCESS); - - /* Do a bunch of writes and erases */ - str_setvar("ho", "aa"); - str_setvar("zo", "nn"); - str_setvar("yo", "CCCCCCCC"); - str_setvar("zooo", "yyyyyyy"); - str_setvar("yo", "AA"); - str_setvar("ho", 0); - str_setvar("yi", "BBB"); - str_setvar("yi", "AA"); - str_setvar("hixx", 0); - str_setvar("yo", "BBB"); - str_setvar("zo", ""); - str_setvar("hi", "bbb"); - str_setvar("ho", "cccccc"); - str_setvar("yo", ""); - str_setvar("zo", "ggggg"); - - /* What do we expect to find? */ - TEST_ASSERT(str_matches("hi", "bbb")); - TEST_ASSERT(str_matches("hixx", 0)); - TEST_ASSERT(str_matches("ho", "cccccc")); - TEST_ASSERT(str_matches("yi", "AA")); - TEST_ASSERT(str_matches("yo", 0)); - TEST_ASSERT(str_matches("zo", "ggggg")); - TEST_ASSERT(str_matches("zooo", "yyyyyyy")); - - return EC_SUCCESS; -} - -static int weird_keys(void) -{ - uint8_t keyA[255]; - uint8_t keyB[255]; - const char *valA = "this is A"; - const char *valB = "THIS IS b"; - int i; - const struct tuple *t; - - erase_flash(); - TEST_ASSERT(initvars() == EC_SUCCESS); - - for (i = 0; i < 255; i++) { - keyA[i] = i; - keyB[i] = 255 - i; - } - - TEST_ASSERT(setvar(keyA, sizeof(keyA), - valA, strlen(valA)) == EC_SUCCESS); - - TEST_ASSERT(setvar(keyB, sizeof(keyB), - valB, strlen(valB)) == EC_SUCCESS); - - TEST_ASSERT(writevars() == EC_SUCCESS); - - t = getvar(keyA, sizeof(keyA)); - TEST_ASSERT(t); - TEST_ASSERT(t->val_len == strlen(valA)); - TEST_ASSERT(memcmp(tuple_val(t), valA, strlen(valA)) == 0); - - t = getvar(keyB, sizeof(keyB)); - TEST_ASSERT(t); - TEST_ASSERT(t->val_len == strlen(valB)); - TEST_ASSERT(memcmp(tuple_val(t), valB, strlen(valB)) == 0); - - return EC_SUCCESS; -} - -static int weird_values(void) -{ - const char *keyA = "this is A"; - const char *keyB = "THIS IS b"; - char valA[255]; - char valB[255]; - int i; - const struct tuple *t; - - erase_flash(); - TEST_ASSERT(initvars() == EC_SUCCESS); - - for (i = 0; i < 255; i++) { - valA[i] = i; - valB[i] = 255 - i; - } - - TEST_ASSERT(setvar(keyA, strlen(keyA), - valA, sizeof(valA)) == EC_SUCCESS); - TEST_ASSERT(str_setvar("c", "CcC") == EC_SUCCESS); - TEST_ASSERT(setvar(keyB, strlen(keyB), - valB, sizeof(valB)) == EC_SUCCESS); - TEST_ASSERT(str_setvar("d", "dDd") == EC_SUCCESS); - - TEST_ASSERT(writevars() == EC_SUCCESS); - - t = getvar(keyA, strlen(keyA)); - TEST_ASSERT(t); - TEST_ASSERT(memcmp(tuple_val(t), valA, sizeof(valA)) == 0); - - t = getvar(keyB, strlen(keyB)); - TEST_ASSERT(t); - TEST_ASSERT(memcmp(tuple_val(t), valB, sizeof(valB)) == 0); - - TEST_ASSERT(str_matches("c", "CcC")); - TEST_ASSERT(str_matches("d", "dDd")); - - return EC_SUCCESS; -} - -static int fill_it_up(void) -{ - int i, n; - char key[20]; - - erase_flash(); - TEST_ASSERT(initvars() == EC_SUCCESS); - - /* - * Some magic numbers here, because we want to use up 10 bytes at a - * time and end up with exactly 9 free bytes left. - */ - TEST_ASSERT(CONFIG_FLASH_NVMEM_VARS_USER_SIZE % 10 == 0); - n = CONFIG_FLASH_NVMEM_VARS_USER_SIZE / 10; - TEST_ASSERT(n < 1000); - - /* Fill up the storage */ - for (i = 0; i < n - 1; i++) { - /* 3-byte header, 5-char key, 2-char val, == 10 chars */ - snprintf(key, sizeof(key), "kk%03d", i); - TEST_ASSERT(setvar(key, 5, "aa", 2) == EC_SUCCESS); - } - - /* - * Should be nine bytes left in rbuf (because we need one more '\0' at - * the end). This won't fit. - */ - TEST_ASSERT(setvar("kk999", 5, "aa", 2) == EC_ERROR_OVERFLOW); - /* But this will. */ - TEST_ASSERT(setvar("kk999", 5, "a", 1) == EC_SUCCESS); - /* And this, because it replaces a previous entry */ - TEST_ASSERT(setvar("kk000", 5, "bc", 2) == EC_SUCCESS); - /* But this still won't fit */ - TEST_ASSERT(setvar("kk999", 5, "de", 2) == EC_ERROR_OVERFLOW); - - return EC_SUCCESS; -} - -void run_test(void) -{ - test_reset(); - - RUN_TEST(check_init); - RUN_TEST(simple_write); - RUN_TEST(simple_search); - RUN_TEST(simple_delete); - RUN_TEST(complex_write); - RUN_TEST(weird_keys); - RUN_TEST(weird_values); - RUN_TEST(fill_it_up); - - test_print_result(); -} diff --git a/test/nvmem_vars.tasklist b/test/nvmem_vars.tasklist deleted file mode 100644 index cc500f5e8f..0000000000 --- a/test/nvmem_vars.tasklist +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/** - * List of enabled tasks in the priority order - * - * The first one has the lowest priority. - * - * For each task, use the macro TASK_TEST(n, r, d, s) where : - * 'n' in the name of the task - * 'r' in the main routine of the task - * 'd' in an opaque parameter passed to the routine at startup - * 's' is the stack size in bytes; must be a multiple of 8 - */ -#define CONFIG_TEST_TASK_LIST /* No test task */ diff --git a/test/pinweaver.c b/test/pinweaver.c index 71f8f0387d..079fbe2b88 100644 --- a/test/pinweaver.c +++ b/test/pinweaver.c @@ -16,6 +16,8 @@ #include "test_util.h" +#include + struct pw_test_data_t { union { struct pw_request_t request; @@ -152,13 +154,10 @@ const uint8_t DEFAULT_PCR_DIGEST[] = { /* Config Variables and defines for Mocks. */ -struct tuple MOCK_pw_tuple; struct pw_long_term_storage_t MOCK_pw_long_term_storage; struct pw_log_storage_t MOCK_pw_log_storage; int MOCK_getvar_ret = EC_SUCCESS; int MOCK_setvar_ret = EC_SUCCESS; -int MOCK_writevars_ret = EC_SUCCESS; -void *MOCK_tuple_val_ret; const uint8_t *MOCK_rand_bytes_src; size_t MOCK_rand_bytes_offset; @@ -342,7 +341,6 @@ static void setup_storage(int num_operations) { MOCK_getvar_ret = EC_SUCCESS; MOCK_setvar_ret = EC_SUCCESS; - MOCK_writevars_ret = EC_SUCCESS; memset(&MOCK_pw_long_term_storage, 0, sizeof(MOCK_pw_long_term_storage)); @@ -470,7 +468,6 @@ static void setup_reset_tree_defaults(struct merkle_tree_t *merkle_tree, MOCK_rand_bytes_len = sizeof(EMPTY_TREE.key_derivation_nonce); MOCK_appkey_derive_fail = EC_SUCCESS; MOCK_setvar_ret = EC_SUCCESS; - MOCK_writevars_ret = EC_SUCCESS; } static void setup_insert_leaf_defaults(struct merkle_tree_t *merkle_tree, @@ -513,7 +510,6 @@ static void setup_insert_leaf_defaults(struct merkle_tree_t *merkle_tree, MOCK_hmac = DEFAULT_HMAC; MOCK_aes_fail = 0; MOCK_setvar_ret = EC_SUCCESS; - MOCK_writevars_ret = EC_SUCCESS; } static void setup_remove_leaf_defaults(struct merkle_tree_t *merkle_tree, @@ -540,7 +536,6 @@ static void setup_remove_leaf_defaults(struct merkle_tree_t *merkle_tree, setup_default_empty_path(request->data.remove_leaf.path_hashes); MOCK_setvar_ret = EC_SUCCESS; - MOCK_writevars_ret = EC_SUCCESS; } static void setup_try_auth_defaults_with_leaf( @@ -598,7 +593,6 @@ static void setup_try_auth_defaults_with_leaf( MOCK_hash_update_cb = auth_hash_update_cb; MOCK_aes_fail = 0; MOCK_setvar_ret = EC_SUCCESS; - MOCK_writevars_ret = EC_SUCCESS; } static void setup_try_auth_defaults(struct merkle_tree_t *merkle_tree, @@ -645,7 +639,6 @@ static void setup_reset_auth_defaults(struct merkle_tree_t *merkle_tree, MOCK_hmac = EMPTY_HMAC; /* Gets overwritten by auth_hash_update_cb. */ MOCK_aes_fail = 0; MOCK_setvar_ret = EC_SUCCESS; - MOCK_writevars_ret = EC_SUCCESS; } static void setup_get_log_defaults(struct merkle_tree_t *merkle_tree, @@ -800,35 +793,57 @@ uint8_t get_current_pcr_digest(const uint8_t bitmask[2], /******************************************************************************/ /* Mock implementations of nvmem_vars functionality. */ -const struct tuple *getvar(const uint8_t *key, uint8_t key_len) +struct tuple *getvar(const uint8_t *key, uint8_t key_len) { + struct tuple *var = NULL; + size_t i; + + const struct { + size_t key_len; + const void *key; + size_t val_size; + const void *val; + } vars[] = { + {sizeof(PW_TREE_VAR) - 1, PW_TREE_VAR, + sizeof(MOCK_pw_long_term_storage), &MOCK_pw_long_term_storage}, + {sizeof(PW_LOG_VAR0) - 1, PW_LOG_VAR0, + sizeof(MOCK_pw_log_storage), &MOCK_pw_log_storage}, + }; + + if (!key || !key_len) + return NULL; + if (MOCK_getvar_ret != EC_SUCCESS) return NULL; - MOCK_pw_tuple.flags = 0; - MOCK_pw_tuple.key_len = key_len; + for (i = 0; i < ARRAY_SIZE(vars); i++) { + if ((key_len != vars[i].key_len) || + memcmp(key, vars[i].key, key_len)) { + continue; + } + var = malloc(sizeof(struct tuple) + key_len + vars[i].val_size); + var->flags = 0; + var->val_len = vars[i].val_size; + memcpy(var->data_ + var->key_len, vars[i].val, var->val_len); + break; + } - if (key_len == (sizeof(PW_TREE_VAR) - 1) && - memcmp(key, PW_TREE_VAR, (sizeof(PW_TREE_VAR) - 1)) == 0) { - MOCK_pw_tuple.val_len = sizeof(MOCK_pw_long_term_storage); - MOCK_tuple_val_ret = &MOCK_pw_long_term_storage; - return &MOCK_pw_tuple; - } else if (key_len == (sizeof(PW_LOG_VAR0) - 1) && - memcmp(key, PW_LOG_VAR0, (sizeof(PW_LOG_VAR0) - 1)) == 0) { - MOCK_pw_tuple.val_len = sizeof(struct pw_log_storage_t); - MOCK_tuple_val_ret = &MOCK_pw_log_storage; - return &MOCK_pw_tuple; - } else - return NULL; + return var; } +int freevar(struct tuple *var) +{ + free(var); + + return EC_SUCCESS; +} const uint8_t *tuple_val(const struct tuple *tpl) { - return MOCK_tuple_val_ret; + return tpl->data_ + tpl->key_len; } -int setvar(const uint8_t *key, uint8_t key_len, - const uint8_t *val, uint8_t val_len) +int setvar(const uint8_t *key, uint8_t key_len, const uint8_t *val, + uint8_t val_len) { if (MOCK_setvar_ret != EC_SUCCESS) return MOCK_setvar_ret; @@ -847,11 +862,6 @@ int setvar(const uint8_t *key, uint8_t key_len, return EC_ERROR_UNKNOWN; } -int writevars(void) -{ - return MOCK_writevars_ret; -} - /******************************************************************************/ /* Mock implementations of TRNG functionality. */ @@ -1214,7 +1224,7 @@ static int handle_reset_tree_nv_fail(void) setup_reset_tree_defaults(&merkle_tree, &buf.request); - MOCK_writevars_ret = PW_ERR_NV_LENGTH_MISMATCH; + MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), PW_ERR_NV_LENGTH_MISMATCH); @@ -1364,7 +1374,7 @@ static int handle_insert_leaf_nv_fail(void) setup_insert_leaf_defaults(&merkle_tree, &buf.request); - MOCK_writevars_ret = PW_ERR_NV_LENGTH_MISMATCH; + MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), PW_ERR_NV_LENGTH_MISMATCH); @@ -1535,7 +1545,7 @@ static int handle_remove_leaf_nv_fail(void) setup_remove_leaf_defaults(&merkle_tree, &buf.request); - MOCK_writevars_ret = PW_ERR_NV_LENGTH_MISMATCH; + MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), PW_ERR_NV_LENGTH_MISMATCH); @@ -1789,7 +1799,7 @@ static int handle_try_auth_nv_fail(void) force_restart_count(0); force_time((timestamp_t){.val = 65 * SECOND}); - MOCK_writevars_ret = PW_ERR_NV_LENGTH_MISMATCH; + MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), PW_ERR_NV_LENGTH_MISMATCH); @@ -2136,7 +2146,7 @@ static int handle_reset_auth_nv_fail(void) setup_reset_auth_defaults(&merkle_tree, &buf.request); - MOCK_writevars_ret = PW_ERR_NV_LENGTH_MISMATCH; + MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), PW_ERR_NV_LENGTH_MISMATCH); diff --git a/test/test_config.h b/test/test_config.h index 22f497bcc0..17e7d6f44d 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -257,53 +257,37 @@ int ncp15wb_calculate_temp(uint16_t adc); #define CONFIG_USB_PD_PORT_COUNT 2 #endif -#ifdef TEST_NVMEM +#if defined(TEST_NVMEM) || defined(TEST_NVMEM_VARS) +#define CONFIG_CRC8 +#define CONFIG_FLASH_ERASED_VALUE32 (-1U) +#define CONFIG_FLASH_LOG +#define CONFIG_FLASH_LOG_BASE CONFIG_PROGRAM_MEMORY_BASE +#define CONFIG_FLASH_LOG_SPACE 0x800 #define CONFIG_FLASH_NVMEM -#define CONFIG_FLASH_NVMEM_OFFSET_A 0x1000 -#define CONFIG_FLASH_NVMEM_OFFSET_B 0x4000 -#define CONFIG_FLASH_NVMEM_BASE_A (CONFIG_PROGRAM_MEMORY_BASE + \ - CONFIG_FLASH_NVMEM_OFFSET_A) -#define CONFIG_FLASH_NVMEM_BASE_B (CONFIG_PROGRAM_MEMORY_BASE + \ - CONFIG_FLASH_NVMEM_OFFSET_B) -#define CONFIG_FLASH_NVMEM_SIZE 0x4000 +#define CONFIG_FLASH_NVMEM_OFFSET_A 0x3d000 +#define CONFIG_FLASH_NVMEM_OFFSET_B 0x7d000 +#define CONFIG_FLASH_NVMEM_BASE_A \ + (CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_NVMEM_OFFSET_A) +#define CONFIG_FLASH_NVMEM_BASE_B \ + (CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_NVMEM_OFFSET_B) +#define CONFIG_FLASH_NEW_NVMEM_BASE_A (CONFIG_FLASH_NVMEM_BASE_A + 0x800) +#define CONFIG_FLASH_NEW_NVMEM_BASE_B (CONFIG_FLASH_NVMEM_BASE_B + 0x800) +#define CONFIG_MALLOC +/* This is legacy NVMEM partition size. */ +#define NVMEM_PARTITION_SIZE 0x3000 +#define NEW_FLASH_HALF_NVMEM_SIZE \ + (NVMEM_PARTITION_SIZE - CONFIG_FLASH_BANK_SIZE) +#define NEW_NVMEM_PARTITION_SIZE (NVMEM_PARTITION_SIZE - CONFIG_FLASH_BANK_SIZE) +#define NEW_NVMEM_TOTAL_PAGES \ + (2 * NEW_NVMEM_PARTITION_SIZE / CONFIG_FLASH_BANK_SIZE) #define CONFIG_SW_CRC - -#define NVMEM_PARTITION_SIZE \ - (CONFIG_FLASH_NVMEM_SIZE / NVMEM_NUM_PARTITIONS) -/* User buffer definitions for test purposes */ -#define NVMEM_USER_2_SIZE 0x201 -#define NVMEM_USER_1_SIZE 0x402 -#define NVMEM_USER_0_SIZE (NVMEM_PARTITION_SIZE - \ - NVMEM_USER_2_SIZE - NVMEM_USER_1_SIZE - \ - sizeof(struct nvmem_tag)) +#define CONFIG_FLASH_NVMEM_VARS #ifndef __ASSEMBLER__ -enum nvmem_users { - NVMEM_USER_0, - NVMEM_USER_1, - NVMEM_USER_2, - NVMEM_NUM_USERS -}; +enum nvmem_users { NVMEM_TPM = 0, NVMEM_CR50, NVMEM_NUM_USERS }; #endif #endif -#ifdef TEST_NVMEM_VARS -#define NVMEM_PARTITION_SIZE 0x3000 -#define CONFIG_FLASH_NVMEM_VARS -#ifndef __ASSEMBLER__ -/* Define the user region numbers */ -enum nvmem_users { - CONFIG_FLASH_NVMEM_VARS_USER_NUM, - NVMEM_NUM_USERS -}; -/* Define a test var. */ -enum nvmem_vars { - NVMEM_VAR_TEST_VAR, -}; -#endif -#define CONFIG_FLASH_NVMEM_VARS_USER_SIZE 600 -#endif /* TEST_NVMEM_VARS */ - #ifdef TEST_PINWEAVER #define CONFIG_DCRYPTO_MOCK #define CONFIG_PINWEAVER -- cgit v1.2.1