diff --git a/azcvmemu.patch b/azcvmemu.patch deleted file mode 100644 index 41a5445f1..000000000 --- a/azcvmemu.patch +++ /dev/null @@ -1,7176 +0,0 @@ -diff --git a/.github/workflows/integration-emu.yml b/.github/workflows/integration-emu.yml -new file mode 100644 -index 0000000..9700175 ---- /dev/null -+++ b/.github/workflows/integration-emu.yml -@@ -0,0 +1,181 @@ -+name: Integration (Emulation Mode) -+ -+# Trigger on pull request events -+on: -+ pull_request: -+ branches: [ feature/AzCVMEmu ] -+ types: [opened, synchronize, reopened] -+ paths-ignore: -+ - "**.md" -+ - "doc/**" -+ workflow_dispatch: -+ -+env: -+ AS: nasm -+ RUST_TOOLCHAIN: 1.83.0 -+ TOOLCHAIN_PROFILE: minimal -+ -+permissions: -+ contents: read -+ -+jobs: -+ build-and-test: -+ name: Build and Test MigTD in Emulation Mode -+ runs-on: ubuntu-22.04 -+ timeout-minutes: 60 -+ -+ steps: -+ # Install first since it's needed to build NASM -+ - name: Install LLVM and Clang -+ uses: KyleMayes/install-llvm-action@a7a1a882e2d06ebe05d5bb97c3e1f8c984ae96fc # v2.0.7 -+ with: -+ version: "10.0" -+ directory: ${{ runner.temp }}/llvm -+ -+ - name: Install libtinfo5 -+ run: sudo apt-get update -y && sudo apt-get install libtinfo5 -y -+ -+ - name: Install NASM -+ uses: ilammy/setup-nasm@72793074d3c8cdda771dba85f6deafe00623038b # v1.5.2 -+ -+ - name: Install build dependencies -+ run: sudo apt-get install build-essential ocaml ocamlbuild automake autoconf libtool wget python-is-python3 libssl-dev git cmake perl libtss2-dev pkg-config -+ -+ - name: Checkout sources -+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 -+ with: -+ submodules: recursive -+ -+ - name: Install Rust toolchain -+ uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 -+ with: -+ profile: ${{ env.TOOLCHAIN_PROFILE }} -+ toolchain: ${{ env.RUST_TOOLCHAIN }} -+ override: true -+ components: rust-src -+ -+ - name: Add x86_64-unknown-none target -+ run: rustup target add x86_64-unknown-none -+ -+ - name: Run preparation script -+ run: bash sh_script/preparation.sh -+ -+ - name: Build MigTD with test features for emulation -+ run: | -+ echo "Building MigTD with AzCVMEmu and test features for emulation testing..." -+ cargo build --release --features "AzCVMEmu,test_disable_ra_and_accept_all" --no-default-features -+ -+ - name: Verify emulation script and binary -+ run: | -+ if [[ ! -f "./migtdemu.sh" ]]; then -+ echo "Error: migtdemu.sh not found" -+ exit 1 -+ fi -+ chmod +x ./migtdemu.sh -+ -+ if [[ ! -f "./target/release/migtd" ]]; then -+ echo "Error: migtd binary not found after build" -+ exit 1 -+ fi -+ -+ echo "Emulation script and binary are ready" -+ -+ - name: Run MigTD emulation tests -+ id: emulation_test -+ run: | -+ echo "Running MigTD emulation tests with both source and destination..." -+ echo "This will start destination, then source, and test the migration flow" -+ echo "Command: ./migtdemu.sh --test --both --no-sudo --log-level info" -+ -+ # Run the test with timeout and capture exit code -+ set +e -+ timeout 300 ./migtdemu.sh --test --both --no-sudo --log-level info -+ EXIT_CODE=$? -+ set -e -+ -+ echo "Test completed with exit code: $EXIT_CODE" -+ -+ if [[ $EXIT_CODE -eq 0 ]]; then -+ echo "✅ Emulation test completed successfully" -+ echo "test_status=success" >> $GITHUB_OUTPUT -+ elif [[ $EXIT_CODE -eq 124 ]]; then -+ echo "❌ Emulation test timed out after 300 seconds" -+ echo "test_status=timeout" >> $GITHUB_OUTPUT -+ exit 1 -+ else -+ echo "❌ Emulation test failed with exit code $EXIT_CODE" -+ echo "test_status=failed" >> $GITHUB_OUTPUT -+ exit $EXIT_CODE -+ fi -+ -+ - name: Check test outputs and logs -+ if: always() -+ run: | -+ echo "=== Test Execution Summary ===" -+ echo "Test status: ${{ steps.emulation_test.outputs.test_status || 'unknown' }}" -+ -+ if [[ -f "dest.out.log" ]]; then -+ DEST_LOG_SIZE=$(wc -l < dest.out.log) -+ echo "Destination log found: $DEST_LOG_SIZE lines" -+ -+ echo "" -+ echo "=== Last 50 lines of destination log ===" -+ tail -n 50 dest.out.log -+ -+ echo "" -+ echo "=== First 20 lines of destination log ===" -+ head -n 20 dest.out.log -+ else -+ echo "No destination log file found" -+ fi -+ -+ # Check for any process dumps or error files -+ if ls core* 1> /dev/null 2>&1; then -+ echo "" -+ echo "=== Core dumps found ===" -+ ls -la core* -+ fi -+ -+ # Show summary of what was tested -+ echo "" -+ echo "=== Test Summary ===" -+ echo "- Built MigTD with AzCVMEmu and test_disable_ra_and_accept_all features" -+ echo "- Ran emulation test with both source and destination instances" -+ echo "- Test mode enabled (mock attestation, no TPM/Azure CVM required)" -+ -+ - name: Upload test artifacts on failure -+ if: failure() -+ uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 -+ with: -+ name: migtd-test-logs-${{ github.run_id }} -+ path: | -+ dest.out.log -+ *.log -+ core* -+ target/release/migtd -+ retention-days: 7 -+ if-no-files-found: ignore -+ -+ - name: Report final status -+ if: always() -+ run: | -+ case "${{ steps.emulation_test.outputs.test_status }}" in -+ "success") -+ echo "🎉 MigTD PR tests passed successfully!" -+ echo "✅ Build completed" -+ echo "✅ Emulation tests passed" -+ echo "The PR is ready for code review." -+ ;; -+ "timeout") -+ echo "⏰ MigTD tests timed out" -+ echo "✅ Build completed" -+ echo "❌ Tests timed out after 5 minutes" -+ echo "Check logs for hanging processes or infinite loops." -+ ;; -+ "failed"|*) -+ echo "❌ MigTD tests failed" -+ echo "✅ Build completed" -+ echo "❌ Emulation tests failed" -+ echo "Check the test logs above and uploaded artifacts for debugging details." -+ ;; -+ esac -diff --git a/.gitignore b/.gitignore -index 8751b1b..96622ad 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -18,6 +18,11 @@ coverage - # migtd-core - clear-*-kvm.img* - fat*.img -+ -+# Test artifacts -+dest.out.log -+*.log -+core* - test_data - *.o - *.obj -diff --git a/Cargo.lock b/Cargo.lock -index 1e0266b..d981865 100644 ---- a/Cargo.lock -+++ b/Cargo.lock -@@ -2,6 +2,21 @@ - # It is not intended for manual editing. - version = 4 - -+[[package]] -+name = "addr2line" -+version = "0.24.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -+dependencies = [ -+ "gimli", -+] -+ -+[[package]] -+name = "adler2" -+version = "2.0.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -+ - [[package]] - name = "ahash" - version = "0.8.11" -@@ -11,7 +26,7 @@ dependencies = [ - "cfg-if", - "once_cell", - "version_check", -- "zerocopy", -+ "zerocopy 0.7.32", - ] - - [[package]] -@@ -121,6 +136,7 @@ dependencies = [ - "spin 0.9.8", - "td-payload", - "tdx-tdcall", -+ "tdx-tdcall-emu", - ] - - [[package]] -@@ -129,6 +145,91 @@ version = "1.1.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -+[[package]] -+name = "az-cvm-vtpm" -+version = "0.7.4" -+source = "git+https://github.com/kinvolk/azure-cvm-tooling#29ef1581561e85a3a2313f80c738aabe064c4bc4" -+dependencies = [ -+ "bincode", -+ "jsonwebkey", -+ "memoffset", -+ "openssl", -+ "serde", -+ "serde-big-array", -+ "serde_json", -+ "sev", -+ "sha2", -+ "thiserror 2.0.16", -+ "tss-esapi", -+ "zerocopy 0.8.26", -+] -+ -+[[package]] -+name = "az-tdx-vtpm" -+version = "0.7.4" -+source = "git+https://github.com/kinvolk/azure-cvm-tooling#29ef1581561e85a3a2313f80c738aabe064c4bc4" -+dependencies = [ -+ "az-cvm-vtpm", -+ "base64-url", -+ "bincode", -+ "serde", -+ "serde_json", -+ "thiserror 2.0.16", -+ "ureq", -+ "zerocopy 0.8.26", -+] -+ -+[[package]] -+name = "backtrace" -+version = "0.3.75" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -+dependencies = [ -+ "addr2line", -+ "cfg-if", -+ "libc", -+ "miniz_oxide", -+ "object", -+ "rustc-demangle", -+ "windows-targets 0.52.6", -+] -+ -+[[package]] -+name = "base64" -+version = "0.13.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -+ -+[[package]] -+name = "base64" -+version = "0.21.7" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" -+ -+[[package]] -+name = "base64" -+version = "0.22.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -+ -+[[package]] -+name = "base64-url" -+version = "3.0.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "38e2b6c78c06f7288d5e3c3d683bde35a79531127c83b087e5d0d77c974b4b28" -+dependencies = [ -+ "base64 0.22.1", -+] -+ -+[[package]] -+name = "bincode" -+version = "1.3.3" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -+dependencies = [ -+ "serde", -+] -+ - [[package]] - name = "bit_field" - version = "0.10.2" -@@ -141,6 +242,32 @@ version = "0.13.2" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -+[[package]] -+name = "bitfield" -+version = "0.14.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" -+ -+[[package]] -+name = "bitfield" -+version = "0.19.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "62a3a774b2fcac1b726922b921ebba5e9fe36ad37659c822cf8ff2c1e0819892" -+dependencies = [ -+ "bitfield-macros", -+] -+ -+[[package]] -+name = "bitfield-macros" -+version = "0.19.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "52511b09931f7d5fe3a14f23adefbc23e5725b184013e96c8419febb61f14734" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+] -+ - [[package]] - name = "bitfield-struct" - version = "0.7.0" -@@ -149,7 +276,7 @@ checksum = "6c2ce686adbebce0ee484a502c440b4657739adbad65eadf06d64f5816ee9765" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.38", -+ "syn 2.0.106", - ] - - [[package]] -@@ -160,9 +287,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - - [[package]] - name = "bitflags" --version = "2.4.1" -+version = "2.9.3" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" -+checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" - - [[package]] - name = "block-buffer" -@@ -173,12 +300,24 @@ dependencies = [ - "generic-array", - ] - -+[[package]] -+name = "bumpalo" -+version = "3.19.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" -+ - [[package]] - name = "byteorder" - version = "1.5.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -+[[package]] -+name = "bytes" -+version = "1.10.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -+ - [[package]] - name = "cc" - version = "1.2.16" -@@ -193,7 +332,7 @@ name = "cc-measurement" - version = "0.1.0" - dependencies = [ - "sha2", -- "zerocopy", -+ "zerocopy 0.7.32", - ] - - [[package]] -@@ -233,7 +372,7 @@ dependencies = [ - "heck", - "proc-macro2", - "quote", -- "syn 2.0.38", -+ "syn 2.0.106", - ] - - [[package]] -@@ -242,6 +381,12 @@ version = "0.5.1" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" - -+[[package]] -+name = "codicon" -+version = "3.0.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "12170080f3533d6f09a19f81596f836854d0fa4867dc32c8172b8474b4e9de61" -+ - [[package]] - name = "colorchoice" - version = "1.0.0" -@@ -323,7 +468,7 @@ dependencies = [ - "openssl-probe", - "openssl-sys", - "schannel", -- "socket2", -+ "socket2 0.4.10", - "winapi", - ] - -@@ -361,7 +506,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.38", -+ "syn 2.0.106", - ] - - [[package]] -@@ -383,12 +528,64 @@ dependencies = [ - "crypto-common", - ] - -+[[package]] -+name = "dirs" -+version = "6.0.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -+dependencies = [ -+ "dirs-sys", -+] -+ -+[[package]] -+name = "dirs-sys" -+version = "0.5.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -+dependencies = [ -+ "libc", -+ "option-ext", -+ "redox_users", -+ "windows-sys 0.59.0", -+] -+ -+[[package]] -+name = "displaydoc" -+version = "0.2.5" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+] -+ - [[package]] - name = "either" - version = "1.9.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -+[[package]] -+name = "enumflags2" -+version = "0.7.12" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" -+dependencies = [ -+ "enumflags2_derive", -+] -+ -+[[package]] -+name = "enumflags2_derive" -+version = "0.7.12" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+] -+ - [[package]] - name = "env_logger" - version = "0.10.1" -@@ -412,6 +609,30 @@ dependencies = [ - "windows-sys 0.48.0", - ] - -+[[package]] -+name = "foreign-types" -+version = "0.3.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -+dependencies = [ -+ "foreign-types-shared", -+] -+ -+[[package]] -+name = "foreign-types-shared" -+version = "0.1.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -+ -+[[package]] -+name = "form_urlencoded" -+version = "1.2.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -+dependencies = [ -+ "percent-encoding", -+] -+ - [[package]] - name = "futures-core" - version = "0.3.31" -@@ -448,15 +669,21 @@ dependencies = [ - - [[package]] - name = "getrandom" --version = "0.2.10" -+version = "0.2.16" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" - dependencies = [ - "cfg-if", - "libc", - "wasi", - ] - -+[[package]] -+name = "gimli" -+version = "0.31.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -+ - [[package]] - name = "hashbrown" - version = "0.14.5" -@@ -497,12 +724,125 @@ dependencies = [ - "windows-sys 0.48.0", - ] - -+[[package]] -+name = "hostname-validator" -+version = "1.1.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" -+ - [[package]] - name = "humantime" - version = "2.1.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -+[[package]] -+name = "icu_collections" -+version = "2.0.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -+dependencies = [ -+ "displaydoc", -+ "potential_utf", -+ "yoke", -+ "zerofrom", -+ "zerovec", -+] -+ -+[[package]] -+name = "icu_locale_core" -+version = "2.0.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -+dependencies = [ -+ "displaydoc", -+ "litemap", -+ "tinystr", -+ "writeable", -+ "zerovec", -+] -+ -+[[package]] -+name = "icu_normalizer" -+version = "2.0.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -+dependencies = [ -+ "displaydoc", -+ "icu_collections", -+ "icu_normalizer_data", -+ "icu_properties", -+ "icu_provider", -+ "smallvec", -+ "zerovec", -+] -+ -+[[package]] -+name = "icu_normalizer_data" -+version = "2.0.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" -+ -+[[package]] -+name = "icu_properties" -+version = "2.0.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" -+dependencies = [ -+ "displaydoc", -+ "icu_collections", -+ "icu_locale_core", -+ "icu_properties_data", -+ "icu_provider", -+ "potential_utf", -+ "zerotrie", -+ "zerovec", -+] -+ -+[[package]] -+name = "icu_properties_data" -+version = "2.0.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" -+ -+[[package]] -+name = "icu_provider" -+version = "2.0.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -+dependencies = [ -+ "displaydoc", -+ "icu_locale_core", -+ "stable_deref_trait", -+ "tinystr", -+ "writeable", -+ "yoke", -+ "zerofrom", -+ "zerotrie", -+ "zerovec", -+] -+ -+[[package]] -+name = "idna" -+version = "1.1.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -+dependencies = [ -+ "idna_adapter", -+ "smallvec", -+ "utf8_iter", -+] -+ -+[[package]] -+name = "idna_adapter" -+version = "1.2.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -+dependencies = [ -+ "icu_normalizer", -+ "icu_properties", -+] -+ - [[package]] - name = "igvm" - version = "0.3.4" -@@ -515,9 +855,9 @@ dependencies = [ - "igvm_defs", - "open-enum", - "range_map_vec", -- "thiserror", -+ "thiserror 1.0.55", - "tracing", -- "zerocopy", -+ "zerocopy 0.7.32", - ] - - [[package]] -@@ -529,9 +869,35 @@ dependencies = [ - "bitfield-struct", - "open-enum", - "static_assertions", -- "zerocopy", -+ "zerocopy 0.7.32", -+] -+ -+[[package]] -+name = "interrupt-emu" -+version = "0.1.0" -+dependencies = [ -+ "lazy_static", -+ "log", -+ "spin 0.9.8", -+] -+ -+[[package]] -+name = "io-uring" -+version = "0.7.10" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -+dependencies = [ -+ "bitflags 2.9.3", -+ "cfg-if", -+ "libc", - ] - -+[[package]] -+name = "iocuddle" -+version = "0.1.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "d8972d5be69940353d5347a1344cb375d9b457d6809b428b05bb1ca2fb9ce007" -+ - [[package]] - name = "is-terminal" - version = "0.4.9" -@@ -555,6 +921,33 @@ version = "1.0.9" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -+[[package]] -+name = "js-sys" -+version = "0.3.77" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -+dependencies = [ -+ "once_cell", -+ "wasm-bindgen", -+] -+ -+[[package]] -+name = "jsonwebkey" -+version = "0.3.5" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "c57c852b14147e2bd58c14fde40398864453403ef632b1101db130282ee6e2cc" -+dependencies = [ -+ "base64 0.13.1", -+ "bitflags 1.3.2", -+ "generic-array", -+ "num-bigint", -+ "serde", -+ "serde_json", -+ "thiserror 1.0.55", -+ "yasna", -+ "zeroize", -+] -+ - [[package]] - name = "lazy_static" - version = "1.4.0" -@@ -570,6 +963,16 @@ version = "0.2.171" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" - -+[[package]] -+name = "libredox" -+version = "0.1.9" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" -+dependencies = [ -+ "bitflags 2.9.3", -+ "libc", -+] -+ - [[package]] - name = "libz-sys" - version = "1.1.12" -@@ -597,6 +1000,12 @@ version = "0.4.10" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" - -+[[package]] -+name = "litemap" -+version = "0.8.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" -+ - [[package]] - name = "lock_api" - version = "0.4.11" -@@ -613,12 +1022,31 @@ version = "0.4.20" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -+[[package]] -+name = "mbox" -+version = "0.7.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "26d142aeadbc4e8c679fc6d93fbe7efe1c021fa7d80629e615915b519e3bc6de" -+dependencies = [ -+ "libc", -+ "stable_deref_trait", -+] -+ - [[package]] - name = "memchr" - version = "2.6.4" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -+[[package]] -+name = "memoffset" -+version = "0.9.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -+dependencies = [ -+ "autocfg", -+] -+ - [[package]] - name = "migtd" - version = "0.5.1" -@@ -627,9 +1055,10 @@ dependencies = [ - "async_io", - "async_runtime", - "attestation", -- "bitfield", -+ "bitfield 0.13.2", - "cc-measurement", - "crypto", -+ "env_logger", - "futures-util", - "lazy_static", - "log", -@@ -646,15 +1075,20 @@ dependencies = [ - "td-logger", - "td-paging", - "td-payload", -+ "td-payload-emu", -+ "td-shim-emu", - "td-shim-interface", -+ "td-shim-interface-emu", - "tdx-tdcall", -+ "tdx-tdcall-emu", -+ "tokio", - "virtio", - "virtio_serial", - "vmcall_raw", - "vsock", - "x86", - "x86_64", -- "zerocopy", -+ "zerocopy 0.7.32", - ] - - [[package]] -@@ -691,6 +1125,83 @@ dependencies = [ - "walkdir", - ] - -+[[package]] -+name = "miniz_oxide" -+version = "0.8.9" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -+dependencies = [ -+ "adler2", -+] -+ -+[[package]] -+name = "mio" -+version = "1.0.4" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -+dependencies = [ -+ "libc", -+ "wasi", -+ "windows-sys 0.59.0", -+] -+ -+[[package]] -+name = "num-bigint" -+version = "0.4.6" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -+dependencies = [ -+ "num-integer", -+ "num-traits", -+] -+ -+[[package]] -+name = "num-derive" -+version = "0.4.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+] -+ -+[[package]] -+name = "num-integer" -+version = "0.1.46" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -+dependencies = [ -+ "num-traits", -+] -+ -+[[package]] -+name = "num-traits" -+version = "0.2.19" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -+dependencies = [ -+ "autocfg", -+] -+ -+[[package]] -+name = "object" -+version = "0.36.7" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -+dependencies = [ -+ "memchr", -+] -+ -+[[package]] -+name = "oid" -+version = "0.2.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "9c19903c598813dba001b53beeae59bb77ad4892c5c1b9b3500ce4293a0d06c2" -+dependencies = [ -+ "serde", -+] -+ - [[package]] - name = "once_cell" - version = "1.18.0" -@@ -714,7 +1225,33 @@ checksum = "8d1296fab5231654a5aec8bf9e87ba4e3938c502fc4c3c0425a00084c78944be" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.38", -+ "syn 2.0.106", -+] -+ -+[[package]] -+name = "openssl" -+version = "0.10.62" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" -+dependencies = [ -+ "bitflags 2.9.3", -+ "cfg-if", -+ "foreign-types", -+ "libc", -+ "once_cell", -+ "openssl-macros", -+ "openssl-sys", -+] -+ -+[[package]] -+name = "openssl-macros" -+version = "0.1.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", - ] - - [[package]] -@@ -723,6 +1260,15 @@ version = "0.1.5" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -+[[package]] -+name = "openssl-src" -+version = "300.5.2+3.5.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" -+dependencies = [ -+ "cc", -+] -+ - [[package]] - name = "openssl-sys" - version = "0.9.98" -@@ -731,10 +1277,17 @@ checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" - dependencies = [ - "cc", - "libc", -+ "openssl-src", - "pkg-config", - "vcpkg", - ] - -+[[package]] -+name = "option-ext" -+version = "0.2.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -+ - [[package]] - name = "pci" - version = "0.1.0" -@@ -749,6 +1302,47 @@ dependencies = [ - "x86", - ] - -+[[package]] -+name = "percent-encoding" -+version = "2.3.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -+ -+[[package]] -+name = "picky-asn1" -+version = "0.8.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "295eea0f33c16be21e2a98b908fdd4d73c04dd48c8480991b76dbcf0cb58b212" -+dependencies = [ -+ "oid", -+ "serde", -+ "serde_bytes", -+] -+ -+[[package]] -+name = "picky-asn1-der" -+version = "0.4.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "5df7873a9e36d42dadb393bea5e211fe83d793c172afad5fb4ec846ec582793f" -+dependencies = [ -+ "picky-asn1", -+ "serde", -+ "serde_bytes", -+] -+ -+[[package]] -+name = "picky-asn1-x509" -+version = "0.12.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "2c5f20f71a68499ff32310f418a6fad8816eac1a2859ed3f0c5c741389dd6208" -+dependencies = [ -+ "base64 0.21.7", -+ "oid", -+ "picky-asn1", -+ "picky-asn1-der", -+ "serde", -+] -+ - [[package]] - name = "pin-project-lite" - version = "0.2.15" -@@ -780,6 +1374,15 @@ dependencies = [ - "td-shim-interface", - ] - -+[[package]] -+name = "potential_utf" -+version = "0.1.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" -+dependencies = [ -+ "zerovec", -+] -+ - [[package]] - name = "powerfmt" - version = "0.2.0" -@@ -788,18 +1391,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - - [[package]] - name = "proc-macro2" --version = "1.0.69" -+version = "1.0.101" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" - dependencies = [ - "unicode-ident", - ] - - [[package]] - name = "quote" --version = "1.0.33" -+version = "1.0.40" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" - dependencies = [ - "proc-macro2", - ] -@@ -810,6 +1413,15 @@ version = "3.2.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "6198999a900fd9cf051f2109ec3b9589b5c67cbfc77ff82c9fdff24aec83aa7b" - -+[[package]] -+name = "rand_core" -+version = "0.6.4" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -+dependencies = [ -+ "getrandom", -+] -+ - [[package]] - name = "range_map_vec" - version = "0.2.0" -@@ -825,6 +1437,26 @@ dependencies = [ - "bitflags 1.3.2", - ] - -+[[package]] -+name = "rdrand" -+version = "0.8.3" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "d92195228612ac8eed47adbc2ed0f04e513a4ccb98175b6f2bd04d963b533655" -+dependencies = [ -+ "rand_core", -+] -+ -+[[package]] -+name = "redox_users" -+version = "0.5.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -+dependencies = [ -+ "getrandom", -+ "libredox", -+ "thiserror 2.0.16", -+] -+ - [[package]] - name = "regex" - version = "1.10.2" -@@ -875,13 +1507,19 @@ dependencies = [ - "sys_time", - ] - -+[[package]] -+name = "rustc-demangle" -+version = "0.1.26" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" -+ - [[package]] - name = "rustix" - version = "0.38.20" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" - dependencies = [ -- "bitflags 2.4.1", -+ "bitflags 2.9.3", - "errno", - "libc", - "linux-raw-sys", -@@ -976,12 +1614,30 @@ dependencies = [ - ] - - [[package]] --name = "serde" --version = "1.0.189" -+name = "serde" -+version = "1.0.189" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -+dependencies = [ -+ "serde_derive", -+] -+ -+[[package]] -+name = "serde-big-array" -+version = "0.5.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" -+dependencies = [ -+ "serde", -+] -+ -+[[package]] -+name = "serde_bytes" -+version = "0.11.17" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -+checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" - dependencies = [ -- "serde_derive", -+ "serde", - ] - - [[package]] -@@ -992,7 +1648,7 @@ checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.38", -+ "syn 2.0.106", - ] - - [[package]] -@@ -1006,6 +1662,32 @@ dependencies = [ - "serde", - ] - -+[[package]] -+name = "sev" -+version = "6.2.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "1750ba11a6a6bba3c220da714caa0226aa34e417dce3975d2953062240717dea" -+dependencies = [ -+ "base64 0.22.1", -+ "bincode", -+ "bitfield 0.19.2", -+ "bitflags 2.9.3", -+ "byteorder", -+ "codicon", -+ "dirs", -+ "hex", -+ "iocuddle", -+ "lazy_static", -+ "libc", -+ "openssl", -+ "rdrand", -+ "serde", -+ "serde-big-array", -+ "serde_bytes", -+ "static_assertions", -+ "uuid", -+] -+ - [[package]] - name = "sha2" - version = "0.10.8" -@@ -1023,6 +1705,18 @@ version = "1.3.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -+[[package]] -+name = "slab" -+version = "0.4.11" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" -+ -+[[package]] -+name = "smallvec" -+version = "1.15.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -+ - [[package]] - name = "socket2" - version = "0.4.10" -@@ -1033,6 +1727,16 @@ dependencies = [ - "winapi", - ] - -+[[package]] -+name = "socket2" -+version = "0.5.10" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -+dependencies = [ -+ "libc", -+ "windows-sys 0.52.0", -+] -+ - [[package]] - name = "spin" - version = "0.5.2" -@@ -1057,6 +1761,12 @@ dependencies = [ - "lock_api", - ] - -+[[package]] -+name = "stable_deref_trait" -+version = "1.2.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -+ - [[package]] - name = "static_assertions" - version = "1.1.0" -@@ -1088,15 +1798,26 @@ dependencies = [ - - [[package]] - name = "syn" --version = "2.0.38" -+version = "2.0.106" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -+checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" - dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", - ] - -+[[package]] -+name = "synstructure" -+version = "0.13.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+] -+ - [[package]] - name = "sys_time" - version = "0.1.0" -@@ -1106,6 +1827,12 @@ dependencies = [ - "x86_64", - ] - -+[[package]] -+name = "target-lexicon" -+version = "0.12.16" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" -+ - [[package]] - name = "td-benchmark" - version = "0.1.0" -@@ -1159,7 +1886,7 @@ dependencies = [ - name = "td-paging" - version = "0.1.0" - dependencies = [ -- "bitfield", -+ "bitfield 0.13.2", - "log", - "spin 0.9.8", - "td-layout", -@@ -1190,7 +1917,17 @@ dependencies = [ - "tdx-tdcall", - "x86", - "x86_64", -- "zerocopy", -+ "zerocopy 0.7.32", -+] -+ -+[[package]] -+name = "td-payload-emu" -+version = "0.0.0-emu" -+dependencies = [ -+ "interrupt-emu", -+ "lazy_static", -+ "spin 0.9.8", -+ "td-payload", - ] - - [[package]] -@@ -1209,7 +1946,15 @@ dependencies = [ - "td-shim-interface", - "tdx-tdcall", - "which", -- "zerocopy", -+ "zerocopy 0.7.32", -+] -+ -+[[package]] -+name = "td-shim-emu" -+version = "0.1.0-emu" -+dependencies = [ -+ "cc-measurement", -+ "zerocopy 0.7.32", - ] - - [[package]] -@@ -1219,7 +1964,16 @@ dependencies = [ - "log", - "r-efi", - "scroll", -- "zerocopy", -+ "zerocopy 0.7.32", -+] -+ -+[[package]] -+name = "td-shim-interface-emu" -+version = "0.1.0-emu" -+dependencies = [ -+ "r-efi", -+ "scroll", -+ "zerocopy 0.7.32", - ] - - [[package]] -@@ -1259,6 +2013,21 @@ dependencies = [ - "x86_64", - ] - -+[[package]] -+name = "tdx-tdcall-emu" -+version = "0.1.0" -+dependencies = [ -+ "az-tdx-vtpm", -+ "bitflags 2.9.3", -+ "interrupt-emu", -+ "lazy_static", -+ "log", -+ "spin 0.9.8", -+ "tdx-tdcall", -+ "tokio", -+ "zerocopy 0.7.32", -+] -+ - [[package]] - name = "termcolor" - version = "1.4.0" -@@ -1273,7 +2042,7 @@ name = "test-td-payload" - version = "0.1.0" - dependencies = [ - "attestation", -- "bitfield", -+ "bitfield 0.13.2", - "bitflags 1.3.2", - "lazy_static", - "linked_list_allocator", -@@ -1293,7 +2062,7 @@ dependencies = [ - "td-shim", - "td-shim-interface", - "tdx-tdcall", -- "zerocopy", -+ "zerocopy 0.7.32", - ] - - [[package]] -@@ -1302,7 +2071,16 @@ version = "1.0.55" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" - dependencies = [ -- "thiserror-impl", -+ "thiserror-impl 1.0.55", -+] -+ -+[[package]] -+name = "thiserror" -+version = "2.0.16" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" -+dependencies = [ -+ "thiserror-impl 2.0.16", - ] - - [[package]] -@@ -1313,7 +2091,18 @@ checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.38", -+ "syn 2.0.106", -+] -+ -+[[package]] -+name = "thiserror-impl" -+version = "2.0.16" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", - ] - - [[package]] -@@ -1333,6 +2122,33 @@ version = "0.1.2" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -+[[package]] -+name = "tinystr" -+version = "0.8.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -+dependencies = [ -+ "displaydoc", -+ "zerovec", -+] -+ -+[[package]] -+name = "tokio" -+version = "1.46.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" -+dependencies = [ -+ "backtrace", -+ "bytes", -+ "io-uring", -+ "libc", -+ "mio", -+ "pin-project-lite", -+ "slab", -+ "socket2 0.5.10", -+ "windows-sys 0.52.0", -+] -+ - [[package]] - name = "tracing" - version = "0.1.41" -@@ -1352,7 +2168,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.38", -+ "syn 2.0.106", - ] - - [[package]] -@@ -1364,6 +2180,39 @@ dependencies = [ - "once_cell", - ] - -+[[package]] -+name = "tss-esapi" -+version = "7.6.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "78ea9ccde878b029392ac97b5be1f470173d06ea41d18ad0bb3c92794c16a0f2" -+dependencies = [ -+ "bitfield 0.14.0", -+ "enumflags2", -+ "getrandom", -+ "hostname-validator", -+ "log", -+ "mbox", -+ "num-derive", -+ "num-traits", -+ "oid", -+ "picky-asn1", -+ "picky-asn1-x509", -+ "regex", -+ "serde", -+ "tss-esapi-sys", -+ "zeroize", -+] -+ -+[[package]] -+name = "tss-esapi-sys" -+version = "0.5.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "535cd192581c2ec4d5f82e670b1d3fbba6a23ccce8c85de387642051d7cad5b5" -+dependencies = [ -+ "pkg-config", -+ "target-lexicon", -+] -+ - [[package]] - name = "typenum" - version = "1.17.0" -@@ -1382,12 +2231,55 @@ version = "0.9.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -+[[package]] -+name = "ureq" -+version = "2.12.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" -+dependencies = [ -+ "base64 0.22.1", -+ "log", -+ "once_cell", -+ "serde", -+ "serde_json", -+ "url", -+] -+ -+[[package]] -+name = "url" -+version = "2.5.7" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" -+dependencies = [ -+ "form_urlencoded", -+ "idna", -+ "percent-encoding", -+ "serde", -+] -+ -+[[package]] -+name = "utf8_iter" -+version = "1.0.4" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -+ - [[package]] - name = "utf8parse" - version = "0.2.1" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -+[[package]] -+name = "uuid" -+version = "1.18.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" -+dependencies = [ -+ "js-sys", -+ "serde", -+ "wasm-bindgen", -+] -+ - [[package]] - name = "vcpkg" - version = "0.2.15" -@@ -1439,8 +2331,10 @@ dependencies = [ - "rust_std_stub", - "spin 0.9.8", - "td-payload", -+ "td-payload-emu", - "td-shim-interface", - "tdx-tdcall", -+ "tdx-tdcall-emu", - ] - - [[package]] -@@ -1491,6 +2385,64 @@ version = "0.11.0+wasi-snapshot-preview1" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -+[[package]] -+name = "wasm-bindgen" -+version = "0.2.100" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -+dependencies = [ -+ "cfg-if", -+ "once_cell", -+ "rustversion", -+ "wasm-bindgen-macro", -+] -+ -+[[package]] -+name = "wasm-bindgen-backend" -+version = "0.2.100" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -+dependencies = [ -+ "bumpalo", -+ "log", -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+ "wasm-bindgen-shared", -+] -+ -+[[package]] -+name = "wasm-bindgen-macro" -+version = "0.2.100" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -+dependencies = [ -+ "quote", -+ "wasm-bindgen-macro-support", -+] -+ -+[[package]] -+name = "wasm-bindgen-macro-support" -+version = "0.2.100" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+ "wasm-bindgen-backend", -+ "wasm-bindgen-shared", -+] -+ -+[[package]] -+name = "wasm-bindgen-shared" -+version = "0.2.100" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -+dependencies = [ -+ "unicode-ident", -+] -+ - [[package]] - name = "which" - version = "5.0.0" -@@ -1683,6 +2635,12 @@ version = "0.52.6" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -+[[package]] -+name = "writeable" -+version = "0.6.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" -+ - [[package]] - name = "x86" - version = "0.47.0" -@@ -1733,6 +2691,39 @@ dependencies = [ - "xshell", - ] - -+[[package]] -+name = "yasna" -+version = "0.4.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "e262a29d0e61ccf2b6190d7050d4b237535fc76ce4c1210d9caa316f71dffa75" -+dependencies = [ -+ "num-bigint", -+] -+ -+[[package]] -+name = "yoke" -+version = "0.8.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -+dependencies = [ -+ "serde", -+ "stable_deref_trait", -+ "yoke-derive", -+ "zerofrom", -+] -+ -+[[package]] -+name = "yoke-derive" -+version = "0.8.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+ "synstructure", -+] -+ - [[package]] - name = "zerocopy" - version = "0.7.32" -@@ -1740,7 +2731,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" - dependencies = [ - "byteorder", -- "zerocopy-derive", -+ "zerocopy-derive 0.7.32", -+] -+ -+[[package]] -+name = "zerocopy" -+version = "0.8.26" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" -+dependencies = [ -+ "zerocopy-derive 0.8.26", - ] - - [[package]] -@@ -1751,7 +2751,39 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.38", -+ "syn 2.0.106", -+] -+ -+[[package]] -+name = "zerocopy-derive" -+version = "0.8.26" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+] -+ -+[[package]] -+name = "zerofrom" -+version = "0.1.6" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -+dependencies = [ -+ "zerofrom-derive", -+] -+ -+[[package]] -+name = "zerofrom-derive" -+version = "0.1.6" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+ "synstructure", - ] - - [[package]] -@@ -1759,3 +2791,50 @@ name = "zeroize" - version = "1.8.1" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -+dependencies = [ -+ "zeroize_derive", -+] -+ -+[[package]] -+name = "zeroize_derive" -+version = "1.4.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+] -+ -+[[package]] -+name = "zerotrie" -+version = "0.2.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -+dependencies = [ -+ "displaydoc", -+ "yoke", -+ "zerofrom", -+] -+ -+[[package]] -+name = "zerovec" -+version = "0.11.4" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" -+dependencies = [ -+ "yoke", -+ "zerofrom", -+ "zerovec-derive", -+] -+ -+[[package]] -+name = "zerovec-derive" -+version = "0.11.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.106", -+] -diff --git a/Cargo.toml b/Cargo.toml -index 61fc1cf..2ab026d 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -24,7 +24,8 @@ default-members = [ - - exclude = [ - "deps/td-shim", -- "deps/rustls" -+ "deps/rustls", -+ "deps/td-shim-AzCVMEmu" - ] - - resolver = "2" -@@ -44,3 +45,4 @@ lto = true - - [patch.crates-io] - ring = { path = "deps/td-shim/library/ring" } -+az-tdx-vtpm = { version = "0.7", git = "https://github.com/kinvolk/azure-cvm-tooling", package = "az-tdx-vtpm" } -diff --git a/deps/td-shim-AzCVMEmu/README.md b/deps/td-shim-AzCVMEmu/README.md -new file mode 100644 -index 0000000..7cd62e5 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/README.md -@@ -0,0 +1,136 @@ -+# TDX TDCALL TCP Emulation for Azure CVM -+ -+This crate provides a drop-in replacement for the original `tdx-tdcall` crate that emulates TDX VMCALL operations using TCP transport. This enables MigTD development and testing in non-TDX environments. -+ -+## Architecture -+ -+The emulation library: -+- **Re-exports all standard tdx-tdcall functions** unchanged for compatibility -+- **Emulates only MigTD-specific vmcalls** via TCP transport -+- **Maintains the exact same API** as the original tdx-tdcall -+- **Uses feature flags** to enable/disable emulation -+ -+## Usage -+ -+### 1. Building with TCP Emulation -+ -+To build MigTD with TCP emulation instead of real TDX vmcalls: -+ -+```bash -+# Build with AzCVMEmu emulation -+cargo image --no-default-features --features stack-guard,vmcall-raw,azcvm-emulation -+ -+# Or set in Cargo.toml dependencies -+[dependencies.tdx-tdcall] -+path = "../deps/td-shim-AzCVMEmu/tdx-tdcall" -+``` -+ -+### 2. Configuration -+ -+The TCP emulation connects to a configurable endpoint: -+ -+```rust -+// Default configuration -+TcpEmulationConfig { -+ remote_addr: "127.0.0.1:9001", // TCP server address -+ connection_timeout: Duration::from_secs(10), -+ operation_timeout: Duration::from_secs(30), -+ max_retries: 3, -+} -+``` -+ -+### 3. Protocol -+ -+The emulation uses a simple TCP protocol with serialized packets: -+ -+```rust -+struct MigTdTcpPacket { -+ operation: MigTdOperation, // Send/Receive/WaitForRequest/ReportStatus -+ mig_request_id: u64, // Migration context ID -+ sequence_id: u32, // Packet sequence number -+ status: u32, // Operation status -+ data_length: u32, // Payload length -+ payload: Vec, // Actual data -+} -+``` -+ -+## Emulated Functions -+ -+The following TDX MigTD vmcalls are emulated via TCP: -+ -+- `tdvmcall_migtd_send()` - Sends data to remote MigTD -+- `tdvmcall_migtd_receive()` - Receives data from remote MigTD -+- `tdvmcall_migtd_waitforrequest()` - Waits for migration requests -+- `tdvmcall_migtd_reportstatus()` - Reports migration status -+ -+All other tdx-tdcall functions pass through to the original implementation. -+ -+## Integration with MigTD -+ -+To use this emulation in MigTD: -+ -+### 1. Update vmcall_raw dependency -+ -+In `src/devices/vmcall_raw/Cargo.toml`: -+ -+```toml -+[dependencies.tdx-tdcall] -+# Use emulated version for AzCVMEmu builds -+path = "../../../deps/td-shim-AzCVMEmu/tdx-tdcall" -+ -+# Or use original for real TDX builds -+# path = "../../../deps/td-shim/tdx-tdcall" -+``` -+ -+### 2. Add build feature -+ -+In main `Cargo.toml`: -+ -+```toml -+[features] -+azcvm-emulation = ["vmcall_raw/AzCVMEmu"] -+``` -+ -+### 3. Build commands -+ -+```bash -+# Real TDX build -+cargo image --no-default-features --features stack-guard,vmcall-raw -+ -+# AzCVMEmu emulation build -+cargo image --no-default-features --features stack-guard,vmcall-raw,azcvm-emulation -+``` -+ -+## Testing -+ -+You can test the emulation by running a simple TCP server that responds to MigTD packets: -+ -+```bash -+# Start a test server on port 9001 -+nc -l 9001 -+ -+# Or use the existing MigTD TCP transport implementation -+# in src/devices/tcp_transport as a reference -+``` -+ -+## Benefits -+ -+1. **No code changes** to vmcall_raw or other MigTD components -+2. **Drop-in replacement** - same API as original tdx-tdcall -+3. **Feature-gated** - can switch between real and emulated at build time -+4. **Development-friendly** - enables testing without TDX hardware -+5. **Clean separation** - emulation code isolated from main MigTD -+ -+## Architecture Diagram -+ -+``` -+MigTD vmcall_raw -+ ↓ -+tdx-tdcall (this emulation crate) -+ ↓ -+[Real TDX] OR [TCP Transport] -+ ↓ -+ VMM/Host ←→ Remote MigTD -+``` -+ -+This design allows the same MigTD code to work in both real TDX environments and emulated TCP environments without any modifications. -diff --git a/deps/td-shim-AzCVMEmu/interrupt-emu/Cargo.toml b/deps/td-shim-AzCVMEmu/interrupt-emu/Cargo.toml -new file mode 100644 -index 0000000..560e897 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/interrupt-emu/Cargo.toml -@@ -0,0 +1,14 @@ -+[package] -+name = "interrupt-emu" -+version = "0.1.0" -+edition = "2021" -+license = "BSD-2-Clause-Patent" -+ -+[lib] -+name = "interrupt_emu" -+path = "src/lib.rs" -+ -+[dependencies] -+lazy_static = { version = "1.4", features = ["spin_no_std"] } -+spin = "0.9" -+log = "0.4" -diff --git a/deps/td-shim-AzCVMEmu/interrupt-emu/src/lib.rs b/deps/td-shim-AzCVMEmu/interrupt-emu/src/lib.rs -new file mode 100644 -index 0000000..f1f5e05 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/interrupt-emu/src/lib.rs -@@ -0,0 +1,30 @@ -+// Interrupt emulation registry for AzCVMEmu. -+// Stores callbacks by vector and allows software-triggered dispatch. -+ -+#![cfg_attr(not(test), no_std)] -+ -+extern crate alloc; -+ -+use lazy_static::lazy_static; -+use spin::Mutex; -+ -+// Match the shape vmcall_raw expects when passing a stack object to callbacks. -+#[repr(C)] -+pub struct InterruptStack; -+ -+pub type Callback = fn(&mut InterruptStack); -+ -+lazy_static! { -+ static ref CALLBACKS: Mutex<[Option; 256]> = Mutex::new([None; 256]); -+} -+ -+pub fn register(vector: u8, cb: Callback) { -+ CALLBACKS.lock()[vector as usize] = Some(cb); -+} -+ -+pub fn trigger(vector: u8) { -+ if let Some(cb) = CALLBACKS.lock()[vector as usize] { -+ let mut stack = InterruptStack; -+ cb(&mut stack); -+ } -+} -diff --git a/deps/td-shim-AzCVMEmu/td-payload-emu/Cargo.toml b/deps/td-shim-AzCVMEmu/td-payload-emu/Cargo.toml -new file mode 100644 -index 0000000..8ab6f2d ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-payload-emu/Cargo.toml -@@ -0,0 +1,13 @@ -+[package] -+name = "td-payload-emu" -+version = "0.0.0-emu" -+edition = "2021" -+license = "BSD-2-Clause-Patent" -+description = "AzCVMEmu shim for td-payload APIs used by vmcall_raw" -+ -+[dependencies] -+# Re-export the real td-payload for most functionality -+td-payload-real = { path = "../../td-shim/td-payload", package = "td-payload", features = ["tdx"] } -+interrupt-emu = { path = "../interrupt-emu", package = "interrupt-emu" } -+lazy_static = { version = "1.4", features = ["spin_no_std"] } -+spin = "0.9" -diff --git a/deps/td-shim-AzCVMEmu/td-payload-emu/src/arch/idt/mod.rs b/deps/td-shim-AzCVMEmu/td-payload-emu/src/arch/idt/mod.rs -new file mode 100644 -index 0000000..7baca87 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-payload-emu/src/arch/idt/mod.rs -@@ -0,0 +1,16 @@ -+use interrupt_emu as intr; -+pub use intr::InterruptStack; -+ -+#[derive(Copy, Clone)] -+pub struct InterruptCallback(fn(&mut InterruptStack)); -+ -+impl InterruptCallback { -+ pub fn new(cb: fn(&mut InterruptStack)) -> Self { Self(cb) } -+ pub fn call(&self, stack: &mut InterruptStack) { (self.0)(stack) } -+} -+ -+pub fn register_interrupt_callback(vector: usize, cb: InterruptCallback) -> Result<(), ()> { -+ // Store raw fn into interrupt-emu registry -+ intr::register(vector as u8, cb.0); -+ Ok(()) -+} -diff --git a/deps/td-shim-AzCVMEmu/td-payload-emu/src/lib.rs b/deps/td-shim-AzCVMEmu/td-payload-emu/src/lib.rs -new file mode 100644 -index 0000000..8406490 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-payload-emu/src/lib.rs -@@ -0,0 +1,23 @@ -+#![cfg_attr(not(test), no_std)] -+ -+extern crate alloc; -+ -+// Re-export most of the real td-payload functionality -+pub use td_payload_real::*; -+ -+// Override specific modules that need emulation behavior -+pub mod arch { -+ // Re-export most arch functionality from real td-payload -+ pub use td_payload_real::arch::*; -+ -+ // Override only the IDT module for emulation -+ pub mod idt; -+} -+ -+pub mod mm { -+ // Re-export most mm functionality from real td-payload -+ pub use td_payload_real::mm::*; -+ -+ // Override only the shared module for emulation -+ pub mod shared; -+} -diff --git a/deps/td-shim-AzCVMEmu/td-payload-emu/src/mm/shared/mod.rs b/deps/td-shim-AzCVMEmu/td-payload-emu/src/mm/shared/mod.rs -new file mode 100644 -index 0000000..b1dd932 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-payload-emu/src/mm/shared/mod.rs -@@ -0,0 +1,29 @@ -+use alloc::vec::Vec; -+ -+pub struct SharedMemory { -+ buf: Vec, -+} -+ -+impl SharedMemory { -+ pub fn new(pages: usize) -> Option { -+ if pages == 0 { return None; } -+ // 4KiB pages typical in TDX environment -+ let size = pages.checked_mul(4096)?; -+ Some(Self { buf: Vec::from_iter(core::iter::repeat(0u8).take(size)) }) -+ } -+ -+ pub fn as_mut_bytes(&mut self) -> &mut [u8] { -+ &mut self.buf -+ } -+ -+ // Add missing methods for API compatibility with real td-payload -+ pub fn as_bytes(&self) -> &[u8] { -+ &self.buf -+ } -+ -+ pub fn copy_to_private_shadow(&mut self) -> Option<&[u8]> { -+ // In emulation mode, just return the buffer directly since we're not dealing with -+ // actual shared/private memory conversion like in real TDX -+ Some(&self.buf) -+ } -+} -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/Cargo.toml b/deps/td-shim-AzCVMEmu/td-shim-interface/Cargo.toml -new file mode 100644 -index 0000000..f79c5c4 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/Cargo.toml -@@ -0,0 +1,18 @@ -+[package] -+name = "td-shim-interface-emu" -+version = "0.1.0-emu" -+license = "BSD-2-Clause-Patent" -+description = "TD-shim interface emulation for Azure CVM environment" -+ -+edition = "2018" -+keywords = ["td-shim", "TDX", "intel", "azure", "emulation"] -+ -+[dependencies] -+scroll = { version = "0.10", default-features = false, features = ["derive"] } -+r-efi = "3.2.0" -+zerocopy = { version = "0.7", features = ["derive"] } -+ -+[features] -+default = ["std"] -+no-metadata-checks = [] -+std = [] -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/acpi.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/acpi.rs -new file mode 100644 -index 0000000..ac9addd ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/acpi.rs -@@ -0,0 +1,77 @@ -+// Copyright (c) 2022 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! ACPI emulation for td-shim-interface-emu -+//! Provides minimal ACPI types needed by migtd -+ -+use zerocopy::{AsBytes, FromBytes, FromZeroes}; -+ -+#[repr(C, packed)] -+#[derive(Default, AsBytes, FromBytes, FromZeroes, Copy, Clone)] -+pub struct GenericSdtHeader { -+ pub signature: [u8; 4], -+ pub length: u32, -+ pub revision: u8, -+ pub checksum: u8, -+ pub oem_id: [u8; 6], -+ pub oem_table_id: [u8; 8], -+ pub oem_revision: u32, -+ pub creator_id: u32, -+ pub creator_revision: u32, -+} -+ -+impl GenericSdtHeader { -+ pub fn new(signature: &[u8; 4], length: u32, revision: u8) -> Self { -+ Self { -+ signature: *signature, -+ length, -+ revision, -+ checksum: 0, -+ oem_id: *b"INTEL ", -+ oem_table_id: *b"EMULATED", -+ oem_revision: 1, -+ creator_id: u32::from_le_bytes(*b"EMUL"), -+ creator_revision: 1, -+ } -+ } -+ -+ pub fn set_checksum(&mut self, checksum: u8) { -+ self.checksum = checksum; -+ } -+} -+ -+#[repr(C, packed)] -+#[derive(Default, AsBytes, FromBytes, FromZeroes, Copy, Clone)] -+pub struct Ccel { -+ pub header: GenericSdtHeader, -+ pub cc_type: u8, -+ pub cc_subtype: u8, -+ pub reserved: u16, -+ pub laml: u64, -+ pub lasa: u64, -+} -+ -+impl Ccel { -+ pub fn new(cc_type: u8, cc_subtype: u8, laml: u64, lasa: u64) -> Ccel { -+ let mut ccel = Ccel { -+ header: GenericSdtHeader::new(b"CCEL", core::mem::size_of::() as u32, 1), -+ cc_type, -+ cc_subtype, -+ reserved: 0, -+ laml, -+ lasa, -+ }; -+ ccel.checksum(); -+ ccel -+ } -+ -+ pub fn checksum(&mut self) { -+ self.header.checksum = 0; -+ self.header.set_checksum(calculate_checksum(self.as_bytes())); -+ } -+} -+ -+pub fn calculate_checksum(data: &[u8]) -> u8 { -+ (255 - data.iter().fold(0u8, |acc, x| acc.wrapping_add(*x))).wrapping_add(1) -+} -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/file_ops.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/file_ops.rs -new file mode 100644 -index 0000000..56a5a7c ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/file_ops.rs -@@ -0,0 +1,142 @@ -+// Copyright (c) 2022-2025 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! File operations for AzCVMEmu emulation -+//! -+//! This module provides file reading functionality that can interface -+//! with the host system's file system in emulated environments. -+ -+extern crate alloc; -+use alloc::vec::Vec; -+ -+#[cfg(feature = "std")] -+use std::fs; -+#[cfg(feature = "std")] -+use std::path::Path; -+ -+/// File reader function type -+pub type FileReader = fn(&str) -> Option>; -+ -+/// Simple file reader implementation for basic file I/O -+/// -+/// This function attempts to read a file from the filesystem. -+/// It's designed to work in environments where basic file I/O is available. -+pub fn simple_file_reader(path: &str) -> Option> { -+ // In a real implementation, this would use the host's file system -+ // For demonstration, we'll simulate file reading with some basic logic -+ -+ // Try to read the file using a simple approach -+ // This is a placeholder that would be replaced with actual file I/O -+ match path { -+ "/tmp/migtd_policy.bin" => { -+ // Simulate reading a policy file -+ Some(b"AzCVMEmu file-based policy data".to_vec()) -+ } -+ "/tmp/migtd_root_ca.bin" => { -+ // Simulate reading a root CA file -+ Some(b"AzCVMEmu file-based root CA data".to_vec()) -+ } -+ _ => { -+ // File not found or unsupported path -+ None -+ } -+ } -+} -+ -+/// Read file contents using pattern matching -+/// -+/// This is a demonstration of how file reading might work in a minimal environment. -+/// In a real implementation, this would use proper file system APIs. -+pub fn pattern_file_reader(path: &str) -> Option> { -+ // This is a placeholder implementation -+ // In a real environment, this would interface with the host OS file system -+ -+ // For now, return simulated data based on the file path -+ match path { -+ path if path.contains("policy") => { -+ Some(b"Simulated policy file content from AzCVMEmu".to_vec()) -+ } -+ path if path.contains("root_ca") => { -+ Some(b"Simulated root CA file content from AzCVMEmu".to_vec()) -+ } -+ _ => { -+ // File not found or unsupported path -+ None -+ } -+ } -+} -+ -+/// Default file reader that provides reasonable test data -+/// -+/// This reader provides default test data for policy and root CA files -+/// when the actual files are not available or in testing scenarios. -+pub fn default_file_reader(path: &str) -> Option> { -+ match path { -+ path if path.contains("policy") => { -+ Some(b"Default AzCVMEmu policy data for testing".to_vec()) -+ } -+ path if path.contains("root_ca") => { -+ Some(b"Default AzCVMEmu root CA data for testing".to_vec()) -+ } -+ _ => None, -+ } -+} -+ -+/// Real file reader implementation using standard library -+/// -+/// This function reads actual files from the host filesystem when std is available. -+/// It's designed for use in AzCVMEmu environments where standard runtime is available. -+#[cfg(feature = "std")] -+pub fn real_file_reader(path: &str) -> Option> { -+ // Verify the path exists and is a regular file -+ let file_path = Path::new(path); -+ if !file_path.exists() || !file_path.is_file() { -+ return None; -+ } -+ -+ // Try to read the file -+ match fs::read(path) { -+ Ok(data) => { -+ // Validate that we actually got some data -+ if data.is_empty() { -+ None -+ } else { -+ Some(data) -+ } -+ } -+ Err(_) => None, -+ } -+} -+ -+/// Real file reader implementation (no-std fallback) -+/// -+/// When std is not available, this falls back to pattern-based simulation. -+#[cfg(not(feature = "std"))] -+pub fn real_file_reader(path: &str) -> Option> { -+ // In no-std environments, fall back to pattern-based reading -+ pattern_file_reader(path) -+} -+ -+/// Initialize file-based emulation with real file reader -+/// -+/// This function sets up the emulation with a real file reader that can -+/// access the host filesystem when std feature is enabled. -+pub fn init_with_real_file_reader() { -+ crate::td_uefi_pi::fv::set_file_reader(real_file_reader); -+} -+ -+/// Initialize file-based emulation with real files at specified paths -+/// -+/// This function loads the policy and root CA files immediately from the filesystem -+/// and stores them in the emulation buffers. -+pub fn init_file_based_emulation_with_real_files(policy_path: &str, root_ca_path: &str) -> bool { -+ // Set the file reader first -+ crate::td_uefi_pi::fv::set_file_reader(real_file_reader); -+ -+ // Load the files immediately -+ let policy_loaded = crate::td_uefi_pi::fv::load_policy_from_file(policy_path); -+ let root_ca_loaded = crate::td_uefi_pi::fv::load_root_ca_from_file(root_ca_path); -+ -+ policy_loaded && root_ca_loaded -+} -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/lib.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/lib.rs -new file mode 100644 -index 0000000..1962ce5 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/lib.rs -@@ -0,0 +1,48 @@ -+// Copyright (c) 2024 Microsoft Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! TD-shim interface emulation for Azure CVM environment -+//! -+//! This crate provides minimal emulation of td-shim-interface functionality -+//! to support the policy crate in Azure CVM environments where the real -+//! td-shim is not available. -+//! -+//! ## File-based Emulation APIs -+//! -+//! For file-based emulation, use the APIs in `td_uefi_pi::fv` module: -+//! - `init_file_based_emulation_with_paths()` - Initialize with custom file paths -+//! - `init_file_based_emulation()` - Initialize with default paths -+//! - `load_policy_data()` / `load_root_ca_data()` - Load data from buffers -+//! - `set_policy_file_path()` / `set_root_ca_file_path()` - Set file paths -+//! - `set_file_reader()` - Set custom file reader function -+//! -+//! ## Usage Example -+//! -+//! ```rust -+//! use td_shim_interface_emu::td_uefi_pi::fv; -+//! -+//! // Initialize file-based emulation with custom paths -+//! fv::init_file_based_emulation_with_paths("/tmp/policy.bin", "/tmp/root_ca.bin"); -+//! -+//! // Or load data directly from buffers -+//! fv::load_policy_data(b"policy data"); -+//! fv::load_root_ca_data(b"root ca data"); -+//! ``` -+ -+#![cfg_attr(not(feature = "std"), no_std)] -+ -+extern crate alloc; -+ -+pub mod td_uefi_pi; -+pub mod file_ops; -+ -+// Re-export key functions for convenience -+pub use td_uefi_pi::fv::{ -+ set_policy_data, -+ set_root_ca_data, -+ load_policy_from_file, -+ load_root_ca_from_file, -+}; -+ -+pub use file_ops::init_file_based_emulation_with_real_files; -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/fv.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/fv.rs -new file mode 100644 -index 0000000..6e44ec1 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/fv.rs -@@ -0,0 +1,146 @@ -+// Copyright (c) 2022 Intel Corporation -+// Copyright (c) 2024 Microsoft Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! Firmware Volume emulation -+//! Provides file-based emulation for policy and root CA files in migtd -+ -+use core::sync::atomic::{AtomicBool, Ordering}; -+use core::ptr; -+use r_efi::efi::Guid; -+use crate::td_uefi_pi::pi::fv::FV_FILETYPE_RAW; -+ -+// Static buffers to store emulated files -+static mut POLICY_BUFFER: [u8; 32768] = [0; 32768]; // 32KB for policy files -+static mut POLICY_SIZE: usize = 0; -+static POLICY_INITIALIZED: AtomicBool = AtomicBool::new(false); -+ -+static mut ROOT_CA_BUFFER: [u8; 4096] = [0; 4096]; // 4KB for root CA files -+static mut ROOT_CA_SIZE: usize = 0; -+static ROOT_CA_INITIALIZED: AtomicBool = AtomicBool::new(false); -+ -+/// Known GUIDs for policy and root CA files in migtd -+const MIGTD_POLICY_FFS_GUID: Guid = Guid::from_fields( -+ 0x0BE92DC3, -+ 0x6221, -+ 0x4C98, -+ 0x87, -+ 0xC1, -+ &[0x8E, 0xEF, 0xFD, 0x70, 0xDE, 0x5A], -+); -+ -+const MIGTD_ROOT_CA_FFS_GUID: Guid = Guid::from_fields( -+ 0xCA437832, -+ 0x4C51, -+ 0x4322, -+ 0xB1, -+ 0x3D, -+ &[0xA2, 0x1B, 0xD0, 0xC8, 0xFF, 0xF6], -+); -+ -+/// Set policy data for emulation -+pub fn set_policy_data(data: &[u8]) -> bool { -+ unsafe { -+ let policy_buffer_ptr = ptr::addr_of_mut!(POLICY_BUFFER); -+ if data.len() > (*policy_buffer_ptr).len() { -+ return false; -+ } -+ -+ let policy_size_ptr = ptr::addr_of_mut!(POLICY_SIZE); -+ (*policy_buffer_ptr)[..data.len()].copy_from_slice(data); -+ *policy_size_ptr = data.len(); -+ } -+ POLICY_INITIALIZED.store(true, Ordering::SeqCst); -+ true -+} -+ -+/// Set root CA data for emulation -+pub fn set_root_ca_data(data: &[u8]) -> bool { -+ unsafe { -+ let root_ca_buffer_ptr = ptr::addr_of_mut!(ROOT_CA_BUFFER); -+ if data.len() > (*root_ca_buffer_ptr).len() { -+ return false; -+ } -+ -+ let root_ca_size_ptr = ptr::addr_of_mut!(ROOT_CA_SIZE); -+ (*root_ca_buffer_ptr)[..data.len()].copy_from_slice(data); -+ *root_ca_size_ptr = data.len(); -+ } -+ ROOT_CA_INITIALIZED.store(true, Ordering::SeqCst); -+ true -+} -+ -+// File reader function type -+type FileReader = fn(&str) -> Option>; -+ -+// Static file reader - set by set_file_reader -+static mut FILE_READER: Option = None; -+ -+/// Set the file reader function for loading files from filesystem -+pub fn set_file_reader(reader: FileReader) { -+ unsafe { -+ let file_reader_ptr = ptr::addr_of_mut!(FILE_READER); -+ *file_reader_ptr = Some(reader); -+ } -+} -+ -+/// Load policy data from file path (if file reader is set) -+pub fn load_policy_from_file(path: &str) -> bool { -+ unsafe { -+ let file_reader_ptr = ptr::addr_of!(FILE_READER); -+ if let Some(reader) = *file_reader_ptr { -+ if let Some(data) = reader(path) { -+ return set_policy_data(&data); -+ } -+ } -+ } -+ false -+} -+ -+/// Load root CA data from file path (if file reader is set) -+pub fn load_root_ca_from_file(path: &str) -> bool { -+ unsafe { -+ let file_reader_ptr = ptr::addr_of!(FILE_READER); -+ if let Some(reader) = *file_reader_ptr { -+ if let Some(data) = reader(path) { -+ return set_root_ca_data(&data); -+ } -+ } -+ } -+ false -+} -+ -+/// Get a file from firmware volume - emulated version supporting policy and root CA files -+/// -+/// This implementation supports common files needed by migtd: -+/// - Policy files (using MIGTD_POLICY_FFS_GUID) -+/// - Root CA files (using MIGTD_ROOT_CA_FFS_GUID) -+/// -+/// Other files will return None -+pub fn get_file_from_fv( -+ _fv_data: &[u8], -+ fv_file_type: u8, -+ file_name: Guid, -+) -> Option<&'static [u8]> { -+ // Only support RAW file type -+ if fv_file_type != FV_FILETYPE_RAW { -+ return None; -+ } -+ -+ if file_name == MIGTD_POLICY_FFS_GUID && POLICY_INITIALIZED.load(Ordering::SeqCst) { -+ unsafe { -+ let policy_buffer_ptr = ptr::addr_of!(POLICY_BUFFER); -+ let policy_size_ptr = ptr::addr_of!(POLICY_SIZE); -+ Some(&(*policy_buffer_ptr)[..*policy_size_ptr]) -+ } -+ } else if file_name == MIGTD_ROOT_CA_FFS_GUID && ROOT_CA_INITIALIZED.load(Ordering::SeqCst) { -+ unsafe { -+ let root_ca_buffer_ptr = ptr::addr_of!(ROOT_CA_BUFFER); -+ let root_ca_size_ptr = ptr::addr_of!(ROOT_CA_SIZE); -+ Some(&(*root_ca_buffer_ptr)[..*root_ca_size_ptr]) -+ } -+ } else { -+ None -+ } -+} -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/hob.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/hob.rs -new file mode 100644 -index 0000000..e10f86f ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/hob.rs -@@ -0,0 +1,45 @@ -+// Copyright (c) 2024 Microsoft Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! Hand-off Block (HOB) emulation for Azure CVM environment -+//! -+//! When using AzCVMEmu with vmcall-raw, HOB emulation is not required. -+//! This module provides minimal stubs that satisfy compilation requirements only. -+ -+// These types are kept minimal since they're not actually used in AzCVMEmu+vmcall-raw mode -+// but are needed for compilation -+ -+/// HOB Header stub -+#[repr(C, packed)] -+#[derive(Debug, Copy, Clone)] -+pub struct Header { -+ pub r#type: u16, -+ pub length: u16, -+ pub reserved: u32, -+} -+ -+/// GUID Extension HOB stub -+#[repr(C, packed)] -+#[derive(Debug, Copy, Clone)] -+pub struct GuidExtension { -+ pub header: Header, -+ pub name: [u8; 16], -+} -+ -+// Minimal stubs of constants for HOB functionality -+pub const HOB_TYPE_END_OF_HOB_LIST: u16 = 0xffff; -+pub const HOB_TYPE_GUID_EXTENSION: u16 = 0x0004; -+pub const HOB_TYPE_RESOURCE_DESCRIPTOR: u16 = 0x0003; -+ -+// These functions are stubs and aren't actually used in AzCVMEmu+vmcall-raw mode -+ -+/// Stub implementation of the align_to_next_hob_offset function -+pub fn align_to_next_hob_offset(_cap: usize, _offset: usize, _length: u16) -> Option { -+ None -+} -+ -+/// Stub implementation of the get_guid_data function -+pub fn get_guid_data(_guided_hob: &[u8]) -> Option<&[u8]> { -+ None -+} -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/mod.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/mod.rs -new file mode 100644 -index 0000000..1eb4366 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/mod.rs -@@ -0,0 +1,9 @@ -+// Copyright (c) 2024 Microsoft Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! UEFI Platform Initialization data structures emulation for Azure CVM. -+ -+pub mod pi; -+pub mod fv; -+pub mod hob; -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/fv.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/fv.rs -new file mode 100644 -index 0000000..5d671f9 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/fv.rs -@@ -0,0 +1,8 @@ -+// Copyright (c) 2022 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! Firmware Volume constants and types -+//! Minimal emulation for migtd usage -+ -+pub const FV_FILETYPE_RAW: u8 = 0x01; -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/guid.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/guid.rs -new file mode 100644 -index 0000000..6427c61 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/guid.rs -@@ -0,0 +1,138 @@ -+// Copyright (c) 2024 Microsoft Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! GUID implementation for Azure CVM emulation environment -+ -+use core::{convert::TryInto, mem::size_of, ptr::slice_from_raw_parts, str::FromStr}; -+use scroll::{Pread, Pwrite}; -+ -+const GUID_STRING_LEN: usize = 36; -+const GUID_SPLITTER: u8 = b'-'; -+ -+/// A GUID is a 128-bit integer (16 bytes) that can be used as a unique identifier. -+/// This is an emulation of the td-shim-interface GUID for Azure CVM environments. -+#[repr(C)] -+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pwrite, Pread)] -+pub struct Guid { -+ f0: u32, -+ f1: u16, -+ f2: u16, -+ f3: [u8; 8], -+} -+ -+#[derive(Debug)] -+pub enum GuidParseError { -+ InvalidInput, -+} -+ -+impl Guid { -+ /// Create a GUID instance from several fields -+ pub const fn from_fields(f0: u32, f1: u16, f2: u16, f3: [u8; 8]) -> Guid { -+ Self { f0, f1, f2, f3 } -+ } -+ -+ /// Get the GUID as a byte array -+ pub fn as_bytes(&self) -> &[u8; 16] { -+ // Safe since the size of Guid is 16 -+ unsafe { -+ (&*slice_from_raw_parts(self as *const Self as *const u8, size_of::())) -+ .try_into() -+ .unwrap() -+ } -+ } -+ -+ /// Create a GUID from a byte array -+ pub fn from_bytes(buffer: &[u8; 16]) -> Guid { -+ let f0 = u32::from_le_bytes(buffer[0..4].try_into().unwrap()); -+ let f1 = u16::from_le_bytes(buffer[4..6].try_into().unwrap()); -+ let f2 = u16::from_le_bytes(buffer[6..8].try_into().unwrap()); -+ let mut f3: [u8; 8] = [0; 8]; -+ f3.copy_from_slice(&buffer[8..]); -+ -+ Self { f0, f1, f2, f3 } -+ } -+} -+ -+impl FromStr for Guid { -+ type Err = GuidParseError; -+ -+ /// Create a GUID instance from a string slice -+ /// Input should follow format strictly: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" -+ /// For example: "F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4" -+ fn from_str(s: &str) -> Result { -+ let b = s.as_bytes(); -+ if b.len() != GUID_STRING_LEN -+ || b[8] != GUID_SPLITTER -+ || b[13] != GUID_SPLITTER -+ || b[18] != GUID_SPLITTER -+ || b[23] != GUID_SPLITTER -+ { -+ return Err(GuidParseError::InvalidInput); -+ } -+ -+ let parse_hex = |s: &str| -> Option { -+ for c in s.as_bytes() { -+ if !c.is_ascii_hexdigit() { -+ return None; -+ } -+ } -+ u64::from_str_radix(s, 16).ok() -+ }; -+ -+ // Parse the string into fields -+ let f0 = parse_hex(&s[0..8]).ok_or(GuidParseError::InvalidInput)? as u32; -+ let f1 = parse_hex(&s[9..13]).ok_or(GuidParseError::InvalidInput)? as u16; -+ let f2 = parse_hex(&s[14..18]).ok_or(GuidParseError::InvalidInput)? as u16; -+ let mut f3 = parse_hex(&s[19..23]).ok_or(GuidParseError::InvalidInput)? << 48; -+ f3 |= parse_hex(&s[24..36]).ok_or(GuidParseError::InvalidInput)?; -+ -+ // f3 is decoded from string so use big endian to encode into bytes -+ Ok(Self { -+ f0, -+ f1, -+ f2, -+ f3: u64::to_be_bytes(f3), -+ }) -+ } -+} -+ -+#[cfg(test)] -+mod test { -+ use super::*; -+ -+ #[test] -+ fn test_guid() { -+ // F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4 -+ let guid_bytes = [ -+ 0x5E, 0x8C, 0x16, 0xF9, 0xB2, 0xCE, 0xaa, 0x4f, 0xB6, 0xBF, 0x32, 0x9B, 0xF3, 0x9F, -+ 0xA1, 0xE4, -+ ]; -+ let guid_field = Guid::from_fields( -+ 0xF9168C5E, -+ 0xCEB2, -+ 0x4faa, -+ [0xB6, 0xBF, 0x32, 0x9B, 0xF3, 0x9F, 0xA1, 0xE4], -+ ); -+ -+ assert_eq!(&guid_bytes, guid_field.as_bytes()); -+ -+ let guid_str = Guid::from_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); -+ assert_eq!(&guid_bytes, guid_str.as_bytes()); -+ -+ let guid_str = Guid::from_str("F9168C5E"); -+ assert!(guid_str.is_err()); -+ -+ let guid_str = Guid::from_str("F9168C5E-CEB2-4faa-B6BF-329"); -+ assert!(guid_str.is_err()); -+ -+ let guid_str = Guid::from_str("F9168C5E-CEB2-4faaB6-BF-329BF39FA1E4"); -+ assert!(guid_str.is_err()); -+ -+ let guid_str = Guid::from_str("+9168C5E-CEB2-4faa-B6BF-329BF39FA1E4"); -+ assert!(guid_str.is_err()); -+ -+ let guid_str = Guid::from_str("F9168C5ECCEB2C4faaCB6BFC329BF39FA1E4"); -+ assert!(guid_str.is_err()); -+ } -+} -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/hob.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/hob.rs -new file mode 100644 -index 0000000..1b0c3e5 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/hob.rs -@@ -0,0 +1,18 @@ -+// Copyright (c) 2024 Microsoft Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! Hand-off Block (HOB) minimal stubs for Azure CVM environment -+//! -+//! When using AzCVMEmu with vmcall-raw, HOB emulation is not required. -+//! This module provides minimal stubs that satisfy compilation requirements only. -+ -+// Re-export types from parent module -+pub use super::super::hob::{Header, GuidExtension}; -+ -+// Re-export constants from parent module -+pub use super::super::hob::{ -+ HOB_TYPE_END_OF_HOB_LIST, -+ HOB_TYPE_GUID_EXTENSION, -+ HOB_TYPE_RESOURCE_DESCRIPTOR, -+}; -diff --git a/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/mod.rs b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/mod.rs -new file mode 100644 -index 0000000..63cb0f4 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim-interface/src/td_uefi_pi/pi/mod.rs -@@ -0,0 +1,9 @@ -+// Copyright (c) 2024 Microsoft Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! Constants and Structures emulation for UEFI Platform Initialization (UEFI-PI) Spec. -+ -+pub mod guid; -+pub mod fv; -+pub mod hob; -diff --git a/deps/td-shim-AzCVMEmu/td-shim/Cargo.toml b/deps/td-shim-AzCVMEmu/td-shim/Cargo.toml -new file mode 100644 -index 0000000..25719e1 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim/Cargo.toml -@@ -0,0 +1,16 @@ -+[package] -+name = "td-shim-emu" -+version = "0.1.0-emu" -+license = "BSD-2-Clause-Patent" -+description = "TD-shim emulation for Azure CVM environment" -+ -+edition = "2018" -+keywords = ["td-shim", "TDX", "intel", "azure", "emulation"] -+ -+[features] -+default = ["std"] -+std = [] -+ -+[dependencies] -+cc-measurement = { path = "../../td-shim/cc-measurement"} -+zerocopy = { version = "0.7", features = ["derive"] } -diff --git a/deps/td-shim-AzCVMEmu/td-shim/src/event_log.rs b/deps/td-shim-AzCVMEmu/td-shim/src/event_log.rs -new file mode 100644 -index 0000000..6e9ad6c ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim/src/event_log.rs -@@ -0,0 +1,379 @@ -+// Copyright (c) 2020 Intel Corporation -+// Copyright (c) 2022 Alibaba Cloud -+// Copyright (c) 2024 Microsoft Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! Event log emulation module -+ -+// This module provides minimal emulation of td-shim event log functionality -+// for Azure CVM environments, including file-based event log storage. -+ -+use cc_measurement::{ -+ log::{CcEventLogError, CcEventLogWriter}, -+ UefiPlatformFirmwareBlob2, EV_EFI_PLATFORM_FIRMWARE_BLOB2, EV_PLATFORM_CONFIG_FLAGS, -+}; -+use core::{mem::size_of, ptr::slice_from_raw_parts, ptr, slice}; -+ -+pub const CCEL_CC_TYPE_TDX: u8 = 2; -+ -+// Mock ACPI and CCEL structures to align with non-AzCVMEmu APIs -+#[derive(Debug, Clone, Copy)] -+pub struct MockCcel { -+ pub lasa: u64, // Event log base address (points to our buffer) -+ pub laml: u32, // Event log length -+} -+ -+impl MockCcel { -+ pub fn new(buffer_ptr: *const u8, buffer_len: usize) -> Self { -+ Self { -+ lasa: buffer_ptr as u64, -+ laml: buffer_len as u32, -+ } -+ } -+ -+ // Mock FromBytes::read_from for compatibility -+ pub fn read_from(_bytes: &[u8]) -> Option { -+ // Initialize the event log if needed and return a proper CCEL -+ init_event_log(); -+ -+ unsafe { -+ let event_log_ptr = ptr::addr_of!(EVENT_LOG); -+ if let Some(log) = (*event_log_ptr).as_ref() { -+ Some(Self::new(log.data.as_ptr(), EVENT_LOG_BUFFER_SIZE)) -+ } else { -+ None -+ } -+ } -+ } -+} -+ -+// Mock ACPI tables function -+pub fn get_acpi_tables() -> Option<&'static [&'static [u8]]> { -+ // Return a mock CCEL table - just need the signature -+ static MOCK_CCEL: &[u8] = b"CCEL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; -+ static TABLES: &[&[u8]] = &[MOCK_CCEL]; -+ Some(TABLES) -+} -+ -+pub const PLATFORM_CONFIG_HOB: &[u8] = b"td_hob\0"; -+pub const PLATFORM_CONFIG_PAYLOAD_PARAMETER: &[u8] = b"td_payload_info\0"; -+pub const PLATFORM_CONFIG_SECURE_POLICY_DB: &[u8] = b"secure_policy_db"; -+pub const PLATFORM_CONFIG_SECURE_AUTHORITY: &[u8] = b"secure_authority"; -+pub const PLATFORM_CONFIG_SVN: &[u8] = b"td_payload_svn\0"; -+pub const PLATFORM_FIRMWARE_BLOB2_PAYLOAD: &[u8] = b"td_payload\0"; -+ -+/// Used to record configuration information into event log -+/// -+/// Defined in td-shim spec 'Table 3.5-4 TD_SHIM_PLATFORM_CONFIG_INFO' -+#[repr(C)] -+#[derive(Debug, Default)] -+pub struct TdShimPlatformConfigInfoHeader { -+ pub descriptor: [u8; 16], -+ pub info_length: u32, -+} -+ -+impl TdShimPlatformConfigInfoHeader { -+ pub fn new(descriptor: &[u8], info_length: u32) -> Option { -+ if descriptor.len() > 16 { -+ return None; -+ } -+ -+ let mut header = Self { -+ info_length, -+ ..Default::default() -+ }; -+ -+ header.descriptor[..descriptor.len()].copy_from_slice(descriptor); -+ Some(header) -+ } -+ -+ pub fn as_bytes(&self) -> &[u8] { -+ unsafe { &*slice_from_raw_parts(self as *const Self as *const u8, size_of::()) } -+ } -+} -+ -+pub fn create_event_log_platform_config( -+ event_log: &mut CcEventLogWriter, -+ mr_index: u32, -+ descriptor: &[u8], -+ data: &[u8], -+) -> Result<(), CcEventLogError> { -+ // Write the `TdShimPlatformConfigInfoHeader + data` into event log -+ let config_header = TdShimPlatformConfigInfoHeader::new(descriptor, data.len() as u32) -+ .ok_or(CcEventLogError::InvalidParameter)?; -+ -+ event_log.create_event_log( -+ mr_index, -+ EV_PLATFORM_CONFIG_FLAGS, -+ &[config_header.as_bytes(), data], -+ data, -+ )?; -+ -+ Ok(()) -+} -+ -+pub fn log_hob_list(hob_list: &[u8], cc_event_log: &mut CcEventLogWriter) { -+ create_event_log_platform_config(cc_event_log, 1, PLATFORM_CONFIG_HOB, hob_list) -+ .expect("Failed to log HOB list to the td event log"); -+} -+ -+pub fn log_payload_binary(payload: &[u8], cc_event_log: &mut CcEventLogWriter) { -+ let blob2 = UefiPlatformFirmwareBlob2::new( -+ PLATFORM_FIRMWARE_BLOB2_PAYLOAD, -+ payload.as_ptr() as u64, -+ payload.len() as u64, -+ ) -+ .expect("Invalid payload binary information or descriptor"); -+ -+ cc_event_log -+ .create_event_log( -+ 2, -+ EV_EFI_PLATFORM_FIRMWARE_BLOB2, -+ &[blob2.as_bytes()], -+ payload, -+ ) -+ .expect("Failed to log HOB list to the td event log"); -+} -+ -+pub fn log_payload_parameter(payload_parameter: &[u8], cc_event_log: &mut CcEventLogWriter) { -+ create_event_log_platform_config( -+ cc_event_log, -+ 2, -+ PLATFORM_CONFIG_PAYLOAD_PARAMETER, -+ payload_parameter, -+ ) -+ .expect("Failed to log HOB list to the td event log"); -+} -+ -+/// SHA384 hash size -+pub const SHA384_DIGEST_SIZE: usize = 48; -+/// SHA384 algorithm identifier -+pub const TPML_ALG_SHA384: u16 = 0x000C; -+/// Event tag for TXT events -+pub const EV_EVENT_TAG: u32 = 0x00000006; -+ -+/// Emulated file-based event log -+// Mock Once implementation to align with non-AzCVMEmu APIs -+pub struct MockOnce { -+ value: Option, -+} -+ -+impl MockOnce { -+ pub const fn new() -> Self { -+ Self { value: None } -+ } -+ -+ pub fn is_completed(&self) -> bool { -+ true // Always return true for emulation -+ } -+ -+ pub fn get(&self) -> Option<&T> { -+ self.value.as_ref() -+ } -+ -+ pub fn call_once(&mut self, f: F) -> &T -+ where -+ F: FnOnce() -> T, -+ { -+ if self.value.is_none() { -+ self.value = Some(f()); -+ } -+ self.value.as_ref().unwrap() -+ } -+} -+ -+// Define the size of the event log buffer as a constant for better maintainability -+pub const EVENT_LOG_BUFFER_SIZE: usize = 32768; // Buffer size 32768 (32KB) -+ -+pub struct EventLogEmulator { -+ data: [u8; EVENT_LOG_BUFFER_SIZE], // Fixed size buffer defined by constant -+ ccel: MockCcel, // Mock CCEL pointing to our buffer -+} -+ -+impl EventLogEmulator { -+ /// Create a new empty event log -+ pub fn new() -> Self { -+ let mut emulator = Self { -+ data: [0u8; EVENT_LOG_BUFFER_SIZE], -+ ccel: MockCcel::new(ptr::null(), 0), // Will be updated below -+ }; -+ -+ // Update CCEL to point to our buffer -+ emulator.ccel = MockCcel::new(emulator.data.as_ptr(), EVENT_LOG_BUFFER_SIZE); -+ emulator -+ } -+ -+ /// Get a reference to the full event log buffer -+ pub fn full_buffer(&self) -> &[u8] { -+ &self.data[..] -+ } -+ -+ /// Get a mutable reference to the full event log buffer -+ pub fn full_buffer_mut(&mut self) -> &mut [u8] { -+ &mut self.data[..] -+ } -+ -+ /// Get the mock CCEL for this event log -+ pub fn get_ccel(&mut self) -> &MockCcel { -+ // Update the CCEL pointer in case the buffer was moved -+ self.ccel = MockCcel::new(self.data.as_ptr(), EVENT_LOG_BUFFER_SIZE); -+ &self.ccel -+ } -+ -+ /// Get event log slice (mimics the non-AzCVMEmu API) -+ pub fn event_log_slice(&mut self) -> &mut [u8] { -+ &mut self.data[..] -+ } -+} -+ -+// Singleton instance of the event log -+static mut EVENT_LOG: Option = None; -+ -+// Mock CCEL singleton to align with non-AzCVMEmu API -+static mut MOCK_CCEL_ONCE: MockOnce = MockOnce::new(); -+ -+/// Mock get_ccel function to align with non-AzCVMEmu API -+pub fn get_ccel() -> Option<&'static MockCcel> { -+ unsafe { -+ // Initialize if needed -+ init_event_log(); -+ -+ let event_log_ptr = ptr::addr_of_mut!(EVENT_LOG); -+ if let Some(log) = (*event_log_ptr).as_mut() { -+ let mock_ccel_ptr = ptr::addr_of_mut!(MOCK_CCEL_ONCE); -+ Some((*mock_ccel_ptr).call_once(|| { -+ MockCcel::new(log.data.as_ptr(), EVENT_LOG_BUFFER_SIZE) -+ })) -+ } else { -+ None -+ } -+ } -+} -+ -+/// Mock event_log_slice function to align with non-AzCVMEmu API -+pub fn event_log_slice(_ccel: &MockCcel) -> &'static mut [u8] { -+ unsafe { -+ let event_log_ptr = ptr::addr_of_mut!(EVENT_LOG); -+ if let Some(log) = (*event_log_ptr).as_mut() { -+ log.event_log_slice() -+ } else { -+ // This shouldn't happen if properly initialized -+ slice::from_raw_parts_mut(ptr::null_mut(), 0) -+ } -+ } -+} -+ -+/// Initialize the event log emulator -+pub fn init_event_log() { -+ unsafe { -+ let event_log_ptr = ptr::addr_of_mut!(EVENT_LOG); -+ if (*event_log_ptr).is_none() { -+ *event_log_ptr = Some(EventLogEmulator::new()); -+ // Add expected event at the beginning of the log -+ // ToDo: Add MigTDCore event to support relevant policy rules -+ populate_tcg_pcr_event_log(); -+ } -+ } -+} -+ -+/// Get a reference to the event log data (returns full buffer for parsing) -+pub fn get_event_log() -> Option<&'static [u8]> { -+ // Initialize the event log if needed -+ init_event_log(); -+ -+ unsafe { -+ let event_log_ptr = ptr::addr_of!(EVENT_LOG); -+ if let Some(log) = (*event_log_ptr).as_ref() { -+ Some(log.full_buffer()) -+ } else { -+ None -+ } -+ } -+} -+ -+/// Get a mutable reference to the full event log buffer -+pub fn get_event_log_mut() -> Option<&'static mut [u8]> { -+ // Initialize the event log if needed -+ init_event_log(); -+ -+ unsafe { -+ let event_log_ptr = ptr::addr_of_mut!(EVENT_LOG); -+ if let Some(log) = (*event_log_ptr).as_mut() { -+ Some(log.full_buffer_mut()) -+ } else { -+ None -+ } -+ } -+} -+ -+fn populate_tcg_pcr_event_log() { -+ unsafe { -+ let event_log_ptr = ptr::addr_of_mut!(EVENT_LOG); -+ if let Some(log) = (*event_log_ptr).as_mut() { -+ // Create a proper TCG event log starting with TcgPcrEventHeader -+ // This is what the policy verification expects to find -+ -+ use cc_measurement::{TcgPcrEventHeader, TcgEfiSpecIdevent}; -+ use core::mem::size_of; -+ use zerocopy::AsBytes; -+ -+ // Create the initial TCG_EfiSpecIDEvent using the default implementation -+ let spec_id_event = TcgEfiSpecIdevent::default(); -+ -+ // Create TcgPcrEventHeader for the first event -+ let pcr_header = TcgPcrEventHeader { -+ mr_index: 0, -+ event_type: 0x80000003, // EV_NO_ACTION -+ digest: [0u8; 20], // SHA1 digest (zeros for EV_NO_ACTION) -+ event_size: size_of::() as u32, -+ }; -+ -+ // Write the headers to the event log -+ let mut offset = 0; -+ -+ // Write TcgPcrEventHeader -+ let pcr_header_bytes = pcr_header.as_bytes(); -+ log.data[offset..offset + pcr_header_bytes.len()].copy_from_slice(pcr_header_bytes); -+ offset += pcr_header_bytes.len(); -+ -+ // Write TcgEfiSpecIdevent -+ let spec_id_bytes = spec_id_event.as_bytes(); -+ log.data[offset..offset + spec_id_bytes.len()].copy_from_slice(spec_id_bytes); -+ -+ // No need to track size - parsing logic will determine the written portion -+ } -+ } -+} -+ -+#[cfg(test)] -+mod test { -+ use super::TdShimPlatformConfigInfoHeader; -+ use core::mem::size_of; -+ -+ #[test] -+ fn test_struct_size() { -+ assert_eq!(size_of::(), 20); -+ } -+ -+ #[test] -+ fn test_tdshim_platform_configinfo_header() { -+ // descriptor length < 16 -+ let descriptor: [u8; 15] = [0; 15]; -+ assert!(TdShimPlatformConfigInfoHeader::new(&descriptor, 0).is_some()); -+ -+ // descriptor length = 16 -+ let descriptor: [u8; 16] = [0; 16]; -+ assert!(TdShimPlatformConfigInfoHeader::new(&descriptor, 0).is_some()); -+ assert_eq!( -+ TdShimPlatformConfigInfoHeader::new(&descriptor, 0) -+ .unwrap() -+ .as_bytes(), -+ [0; 20] -+ ); -+ -+ // descriptor length > 16 -+ let descriptor: [u8; 17] = [0; 17]; -+ assert!(TdShimPlatformConfigInfoHeader::new(&descriptor, 0).is_none()); -+ } -+} -diff --git a/deps/td-shim-AzCVMEmu/td-shim/src/lib.rs b/deps/td-shim-AzCVMEmu/td-shim/src/lib.rs -new file mode 100644 -index 0000000..1d15024 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/td-shim/src/lib.rs -@@ -0,0 +1,14 @@ -+// Copyright (c) 2022 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! Minimal TD-shim emulation for Azure CVM environments -+//! -+//! This crate provides minimal emulation of td-shim functionality needed -+//! to build the policy crate in environments where the full td-shim is not available. -+ -+#![cfg_attr(not(feature = "std"), no_std)] -+ -+extern crate alloc; -+ -+pub mod event_log; -diff --git a/deps/td-shim-AzCVMEmu/tdx-tdcall/Cargo.toml b/deps/td-shim-AzCVMEmu/tdx-tdcall/Cargo.toml -new file mode 100644 -index 0000000..d20b55c ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/tdx-tdcall/Cargo.toml -@@ -0,0 +1,34 @@ -+[package] -+name = "tdx-tdcall-emu" -+version = "0.1.0" -+edition = "2021" -+authors = ["Intel Corporation"] -+description = "Azure CVM Emulation layer for TDX TDCALL interface - TCP-based emulation for MigTD" -+license = "BSD-2-Clause-Patent" -+ -+[dependencies] -+# Original tdx-tdcall for non-emulated functions -+original-tdx-tdcall = { package = "tdx-tdcall", path = "../../td-shim/tdx-tdcall" } -+ -+# Core dependencies for emulation -+tokio = { version = "1.0", features = ["net", "sync", "time", "rt", "rt-multi-thread", "io-util"], default-features = false } -+log = { version = "0.4", default-features = false } -+ -+# Azure CVM specific dependencies -+az-tdx-vtpm = "0.7" -+zerocopy = { version = "0.7", default-features = false } -+ -+# For compatibility with original tdx-tdcall interface -+bitflags = "2.0" -+spin = { version = "0.9", default-features = false, features = ["spin_mutex"] } -+lazy_static = { version = "1.4", features = ["spin_no_std"] } -+interrupt-emu = { path = "../interrupt-emu", package = "interrupt-emu" } -+ -+[features] -+default = [] -+no-std = [] -+test_disable_ra_and_accept_all = [] -+ -+[lib] -+name = "tdx_tdcall_emu" -+path = "src/lib.rs" -diff --git a/deps/td-shim-AzCVMEmu/tdx-tdcall/src/lib.rs b/deps/td-shim-AzCVMEmu/tdx-tdcall/src/lib.rs -new file mode 100644 -index 0000000..6eef04c ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/tdx-tdcall/src/lib.rs -@@ -0,0 +1,130 @@ -+// Copyright (c) 2025 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+#![cfg_attr(feature = "no-std", no_std)] -+ -+//! Azure CVM Emulation layer for TDX TDCALL interface -+//! -+//! This crate provides a drop-in replacement for the original tdx-tdcall crate -+//! that emulates TDX VMCALL operations using TCP transport for development and -+//! testing in non-TDX environments. -+ -+extern crate alloc; -+ -+// Import the original tdx-tdcall as a dependency -+pub use original_tdx_tdcall; -+ -+// Re-export all the standard tdx-tdcall types and constants -+// Re-export error types and constants that are needed -+pub use original_tdx_tdcall::{TdVmcallError, TdcallArgs, TdCallError}; -+ -+// Export constants that we need from the original library -+pub const TDCALL_STATUS_SUCCESS: u64 = 0; -+ -+// Our TDX emulation module -+pub mod tdx_emu; -+ -+// Our emulated tdreport module -+pub mod tdreport_emu; -+ -+// Re-export TDX emulation functions -+pub use tdx_emu::{ -+ init_tcp_emulation_with_mode, start_tcp_server_sync, -+ connect_tcp_client, TcpEmulationMode, -+ tcp_send_data, tcp_receive_data -+}; -+ -+// Re-export the emulated functions -+pub mod tdx { -+ // Re-export all non-MigTD functions from original -+ pub use original_tdx_tdcall::tdx::{ -+ tdcall_get_td_info, tdcall_get_ve_info, -+ tdcall_accept_page, tdcall_vp_read, -+ // Standard VMCALL functions -+ tdvmcall_halt, tdvmcall_sti_halt, -+ tdvmcall_io_read_8, tdvmcall_io_read_16, tdvmcall_io_read_32, -+ tdvmcall_io_write_8, tdvmcall_io_write_16, tdvmcall_io_write_32, -+ tdvmcall_mmio_read, tdvmcall_mmio_write, -+ tdvmcall_mapgpa, tdvmcall_rdmsr, tdvmcall_wrmsr, -+ tdvmcall_cpuid, tdvmcall_setup_event_notify, -+ tdvmcall_service, -+ // Re-export types -+ TdxDigest, -+ }; -+ -+ // Export emulated functions -+ pub use crate::tdx_emu::{ -+ tdvmcall_get_quote, -+ tdvmcall_migtd_waitforrequest, -+ tdvmcall_migtd_reportstatus, -+ tdvmcall_migtd_send_sync as tdvmcall_migtd_send, -+ tdvmcall_migtd_receive_sync as tdvmcall_migtd_receive, -+ tdcall_servtd_rd, -+ tdcall_servtd_wr, -+ tdcall_sys_rd, -+ tdcall_sys_wr, -+ tdcall_extend_rtmr, -+ }; -+} -+ -+// Emulated tdreport module for AzCVMEmu compatibility -+pub mod tdreport { -+ use crate::tdreport_emu::tdcall_report_emulated; -+ use az_tdx_vtpm::tdx::TdReport as AzTdReport; -+ use original_tdx_tdcall::TdCallError; -+ -+ // Re-export some useful constants and types from original -+ pub use original_tdx_tdcall::tdreport::{TD_REPORT_SIZE, TdxReport}; -+ -+ /// Emulated tdcall_report function for AzCVMEmu mode -+ /// Now returns the exact same error type as the original for perfect compatibility -+ pub fn tdcall_report(additional_data: &[u8; 64]) -> Result { -+ let az_td_report = tdcall_report_emulated(additional_data)?; -+ -+ // Create a full 1024-byte TdxReport from the az-tdx-vtpm TdReport -+ // We need to copy the az-tdx-vtpm data into a properly sized buffer -+ let mut tdx_report_bytes = [0u8; TD_REPORT_SIZE]; -+ -+ // Convert az_td_report to bytes using pointer cast -+ let az_report_bytes = unsafe { -+ core::slice::from_raw_parts( -+ &az_td_report as *const AzTdReport as *const u8, -+ core::mem::size_of::() -+ ) -+ }; -+ -+ let copy_size = core::cmp::min(az_report_bytes.len(), TD_REPORT_SIZE); -+ tdx_report_bytes[..copy_size].copy_from_slice(&az_report_bytes[..copy_size]); -+ -+ // Convert the full 1024-byte buffer to TdxReport -+ let tdx_report = unsafe { -+ // Safety: We have a properly sized 1024-byte buffer that matches TdxReport layout -+ core::mem::transmute::<[u8; TD_REPORT_SIZE], TdxReport>(tdx_report_bytes) -+ }; -+ -+ Ok(tdx_report) -+ } -+} -+ -+// Add td_call emulation support -+pub fn td_call(args: &mut TdcallArgs) -> u64 { -+ const TDVMCALL_SYS_RD: u64 = 0x0000b; -+ -+ match args.rax { -+ TDVMCALL_SYS_RD => { -+ match crate::tdx_emu::tdcall_sys_rd(args.rcx) { -+ Ok((rdx, r8)) => { -+ args.rdx = rdx; -+ args.r8 = r8; -+ TDCALL_STATUS_SUCCESS -+ } -+ Err(_) => 0xFFFFFFFFFFFFFFFF, // Error code -+ } -+ } -+ _ => { -+ // Return error for unsupported rax values -+ 0xFFFFFFFFFFFFFFFF // Generic error code -+ } -+ } -+} -diff --git a/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdreport_emu.rs b/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdreport_emu.rs -new file mode 100644 -index 0000000..7fddc34 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdreport_emu.rs -@@ -0,0 +1,238 @@ -+// Copyright (c) 2025 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! TD Report generation emulation for AzCVMEmu mode -+//! -+//! This module provides emulation for TD report generation using vTPM interface -+//! and IMDS for quote generation in Azure CVM environments. -+ -+use alloc::vec::Vec; -+use az_tdx_vtpm::{hcl, tdx, vtpm, imds}; -+use log::{info, debug, error}; -+use original_tdx_tdcall::TdCallError; -+ -+/// Simple error type for internal emulation errors that are not TdCallError -+/// Used only for get_quote_emulated which doesn't need TdCallError compatibility -+#[derive(Debug)] -+pub enum QuoteError { -+ VtpmError, -+ ImdsError, -+ ConversionError, -+} -+ -+/// Emulated TD report generation using vTPM interface -+/// Returns TdCallError directly to match original tdcall_report function signature -+pub fn tdcall_report_emulated(additional_data: &[u8; 64]) -> Result { -+ #[cfg(feature = "test_disable_ra_and_accept_all")] -+ { -+ info!("RATLS: Using mock TD report for test_disable_ra_and_accept_all feature"); -+ return Ok(create_mock_td_report(additional_data)); -+ } -+ -+ info!("RATLS: Using AzCVMEmu vTPM interface for report generation"); -+ -+ // Get the vTPM report with our additional data as user data -+ debug!("RATLS: Getting vTPM report with retry mechanism"); -+ -+ // Retry logic for vTPM report generation -+ let mut vtpm_report = None; -+ let max_retries = 3; -+ -+ for attempt in 1..=max_retries { -+ debug!("RATLS: vTPM report attempt {} of {}", attempt, max_retries); -+ -+ match vtpm::get_report_with_report_data(additional_data) { -+ Ok(report) => { -+ debug!("RATLS: vTPM report obtained successfully on attempt {}", attempt); -+ vtpm_report = Some(report); -+ break; -+ } -+ Err(e) => { -+ error!("RATLS: vTPM report attempt {} failed: {:?}", attempt, e); -+ -+ if attempt < max_retries { -+ debug!("RATLS: Waiting 5 seconds before retry..."); -+ // Wait 5 seconds using std::time in AzCVMEmu mode -+ let start = std::time::Instant::now(); -+ while start.elapsed() < std::time::Duration::from_secs(5) { -+ // Busy wait -+ } -+ } else { -+ error!("RATLS: All vTPM report attempts failed"); -+ // Map to TdCallError::TdxExitInvalidParameters for compatibility -+ return Err(TdCallError::TdxExitInvalidParameters); -+ } -+ } -+ } -+ } -+ -+ let vtpm_report = vtpm_report.ok_or(TdCallError::TdxExitInvalidParameters)?; -+ -+ // Create an HCL report from the vTPM report -+ debug!("RATLS: Creating HCL report from vTPM report"); -+ let hcl_report = match hcl::HclReport::new(vtpm_report) { -+ Ok(report) => { -+ debug!("RATLS: HCL report created successfully"); -+ report -+ } -+ Err(_) => { -+ error!("RATLS: Failed to create HCL report"); -+ return Err(TdCallError::TdxExitInvalidParameters); -+ } -+ }; -+ -+ // Convert the HCL report to a TD report -+ debug!("RATLS: Converting HCL report to TD report"); -+ match tdx::TdReport::try_from(hcl_report) { -+ Ok(report) => { -+ debug!("RATLS: TD report conversion successful"); -+ Ok(report) -+ } -+ Err(_) => { -+ error!("RATLS: Failed to convert HCL report to TD report"); -+ Err(TdCallError::TdxExitInvalidParameters) -+ } -+ } -+} -+ -+/// Emulated quote generation using IMDS interface -+/// This function doesn't need to match original tdcall error types -+pub fn get_quote_emulated(td_report_data: &[u8]) -> Result, QuoteError> { -+ #[cfg(feature = "test_disable_ra_and_accept_all")] -+ { -+ debug!("RATLS: Using mock quote for test_disable_ra_and_accept_all feature"); -+ return Ok(create_mock_quote(td_report_data)); -+ } -+ -+ debug!("RATLS: Getting quote from TD report data (size: {})", td_report_data.len()); -+ -+ // Check if we have a full TD report or just report data -+ let td_report_struct = if td_report_data.len() >= core::mem::size_of::() { -+ // We have a full TD report - use it directly -+ unsafe { -+ *(td_report_data.as_ptr() as *const tdx::TdReport) -+ } -+ } else { -+ // We only have report data (48 bytes) - need to generate a full TD report first -+ debug!("RATLS: Generating TD report from report data"); -+ -+ // Pad or truncate the report data to 64 bytes for tdcall_report_emulated -+ let mut report_data_64 = [0u8; 64]; -+ let copy_len = core::cmp::min(64, td_report_data.len()); -+ report_data_64[..copy_len].copy_from_slice(&td_report_data[..copy_len]); -+ -+ // Generate a full TD report using our emulated function -+ match tdcall_report_emulated(&report_data_64) { -+ Ok(report) => report, -+ Err(e) => { -+ error!("RATLS: Failed to generate TD report from report data: {:?}", e); -+ return Err(QuoteError::ConversionError); -+ } -+ } -+ }; -+ -+ match imds::get_td_quote(&td_report_struct) { -+ Ok(quote) => { -+ info!("Successfully got TD quote from IMDS"); -+ Ok(quote) -+ } -+ Err(e) => { -+ error!("IMDS call failed (expected outside Azure): {:?}", e); -+ error!("RATLS: Failed to get TD quote from IMDS: {:?}", e); -+ Err(QuoteError::ImdsError) -+ } -+ } -+} -+ -+/// Create a mock TD report for testing purposes -+#[cfg(feature = "test_disable_ra_and_accept_all")] -+pub fn create_mock_td_report(additional_data: &[u8; 64]) -> tdx::TdReport { -+ debug!("Creating mock TD report with additional data"); -+ -+ // Import the structures from original tdx-tdcall -+ use original_tdx_tdcall::tdreport::{TdxReport, ReportMac, ReportType, TeeTcbInfo, TdInfo}; -+ -+ // Create a mock TD report with realistic structure but test data -+ let td_report = TdxReport { -+ report_mac: ReportMac { -+ report_type: ReportType { -+ r#type: 0x81, // TDX report type -+ subtype: 0x00, -+ version: 0x00, -+ reserved: 0x00, -+ }, -+ reserved0: [0u8; 12], -+ cpu_svn: [0x01; 16], // Mock CPU SVN -+ tee_tcb_info_hash: [0x42; 48], // Mock hash -+ tee_info_hash: [0x43; 48], // Mock hash -+ report_data: *additional_data, // Include the actual additional data -+ reserved1: [0u8; 32], -+ mac: [0xBB; 32], // Mock MAC -+ }, -+ tee_tcb_info: TeeTcbInfo { -+ valid: [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], -+ tee_tcb_svn: [0x02; 16], -+ mrseam: [0x44; 48], -+ mrsigner_seam: [0x45; 48], -+ attributes: [0x00; 8], -+ reserved: [0u8; 111], -+ }, -+ reserved: [0u8; 17], -+ td_info: TdInfo { -+ attributes: [0x00; 8], -+ xfam: [0x03; 8], -+ mrtd: [0x46; 48], -+ mrconfig_id: [0x47; 48], -+ mrowner: [0x48; 48], -+ mrownerconfig: [0x49; 48], -+ rtmr0: [0x4A; 48], -+ rtmr1: [0x4B; 48], -+ rtmr2: [0x4C; 48], -+ rtmr3: [0x4D; 48], -+ servtd_hash: [0x4E; 48], -+ reserved: [0u8; 64], -+ }, -+ }; -+ -+ debug!("Mock TD report created successfully"); -+ -+ // Convert to az-tdx-vtpm TdReport for compatibility -+ // This is a bit of a hack but necessary for type compatibility -+ unsafe { -+ core::mem::transmute(td_report) -+ } -+} -+ -+/// Create a mock quote for testing purposes -+#[cfg(feature = "test_disable_ra_and_accept_all")] -+pub fn create_mock_quote(td_report_data: &[u8]) -> Vec { -+ debug!("Creating mock quote from TD report data (size: {})", td_report_data.len()); -+ -+ // Create a simplified mock quote structure -+ let mut quote = Vec::new(); -+ -+ // Mock quote header (simplified) -+ quote.extend_from_slice(&[0x04, 0x00]); // Version -+ quote.extend_from_slice(&[0x81, 0x00]); // Attestation key type (TDX) -+ quote.extend_from_slice(&[0x00; 4]); // Reserved -+ quote.extend_from_slice(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); // Mock QE SVN -+ quote.extend_from_slice(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]); // Mock PCE SVN -+ quote.extend_from_slice(&[0x00; 16]); // QE Vendor ID -+ quote.extend_from_slice(&[0xAA; 20]); // User data (mock) -+ -+ // Mock TD report section (include the actual report data for consistency) -+ let report_size = core::cmp::min(td_report_data.len(), 1024); -+ quote.extend_from_slice(&(report_size as u32).to_le_bytes()); // TD report size -+ if report_size > 0 { -+ quote.extend_from_slice(&td_report_data[..report_size]); -+ } -+ -+ // Mock signature section -+ quote.extend_from_slice(&[0x00; 4]); // Signature data size -+ quote.extend_from_slice(&[0xBB; 64]); // Mock ECDSA signature -+ quote.extend_from_slice(&[0xCC; 64]); // Mock public key -+ -+ debug!("Mock quote created with size: {}", quote.len()); -+ quote -+} -diff --git a/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdx_emu.rs b/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdx_emu.rs -new file mode 100644 -index 0000000..c508f38 ---- /dev/null -+++ b/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdx_emu.rs -@@ -0,0 +1,580 @@ -+// Copyright (c) 2025 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! TDX emulation for MigTD operations in AzCVMEmu mode -+//! -+//! This module provides comprehensive emulation for TDX operations including: -+//! - TDVMCALL MigTD functions (waitforrequest, reportstatus, send, receive) -+//! - TDCALL ServTD functions (rd, wr) -+//! - TDCALL SYS functions (rd, wr) -+//! - TCP-based networking for communication between source and destination instances -+ -+use alloc::string::String; -+use alloc::vec::Vec; -+use lazy_static::lazy_static; -+use log::{error, warn}; -+// Use interrupt-emu to fire callbacks registered by upper layers. -+use interrupt_emu as intr; -+use original_tdx_tdcall::{TdCallError, TdVmcallError}; -+use original_tdx_tdcall::tdx::ServtdRWResult; -+use spin::Mutex; -+use std::io::{Read, Write}; -+use std::net::{TcpListener, TcpStream}; -+use std::collections::HashMap; -+ -+/// TCP emulation mode for MigTD -+#[derive(Debug, Clone)] -+pub enum TcpEmulationMode { -+ Client, // Source - connects to destination -+ Server, // Destination - listens for connections -+} -+ -+lazy_static! { -+ /// Global TCP address for emulation -+ static ref TCP_ADDRESS: Mutex> = Mutex::new(None); -+ /// Global TCP mode for emulation -+ static ref TCP_MODE: Mutex> = Mutex::new(None); -+ /// Connected TCP stream for data exchange -+ static ref TCP_STREAM: Mutex> = Mutex::new(None); -+ /// Emulated pending migration request info for waitforrequest -+ static ref MIG_REQUEST: Mutex> = Mutex::new(None); -+ /// Emulated MSK/TDCS field storage keyed by (binding_handle, target_uuid, field_identifier) -+ static ref MSK_FIELDS: Mutex> = Mutex::new(HashMap::new()); -+ /// Emulated global-scope SYS fields keyed by field_identifier -+ static ref SYS_FIELDS: Mutex> = Mutex::new(HashMap::new()); -+} -+ -+/// Emulated migration request info used by tdvmcall_migtd_waitforrequest -+#[derive(Clone, Debug, Default)] -+pub struct EmuMigRequest { -+ pub request_id: u64, -+ pub migration_source: u8, -+ pub target_td_uuid: [u64; 4], -+ pub binding_handle: u64, -+} -+ -+/// Seed the emulation layer with a pending migration request returned by waitforrequest -+pub fn set_emulated_mig_request(req: EmuMigRequest) { -+ *MIG_REQUEST.lock() = Some(req); -+} -+ -+/// Set TCP address and mode for emulation -+pub fn init_tcp_emulation_with_mode(ip: &str, port: u16, mode: TcpEmulationMode) -> Result<(), &'static str> { -+ let tcp_addr = format!("{}:{}", ip, port); -+ -+ // Validate IP address format (basic validation) -+ if ip.is_empty() { -+ return Err("IP address cannot be empty"); -+ } -+ -+ // Set the TCP configuration -+ { -+ let mut addr = TCP_ADDRESS.lock(); -+ *addr = Some(tcp_addr.clone()); -+ } -+ { -+ let mut tcp_mode = TCP_MODE.lock(); -+ *tcp_mode = Some(mode.clone()); -+ } -+ -+ match mode { -+ TcpEmulationMode::Server => { -+ // Server mode setup -+ } -+ TcpEmulationMode::Client => { -+ // Client mode setup -+ } -+ } -+ -+ Ok(()) -+} -+ -+/// Start TCP server for destination instances (blocking call) -+pub fn start_tcp_server_sync(addr: &str) -> Result<(), TdVmcallError> { -+ -+ let listener = TcpListener::bind(addr) -+ .map_err(|e| { -+ error!("Failed to bind TCP listener to {}: {}", addr, e); -+ TdVmcallError::Other -+ })?; -+ -+ // Accept the first connection and store it globally -+ let (stream, _peer_addr) = listener.accept() -+ .map_err(|e| { -+ error!("Failed to accept TCP connection: {}", e); -+ TdVmcallError::Other -+ })?; -+ -+ // Store the stream globally for send/receive operations -+ { -+ let mut tcp_stream = TCP_STREAM.lock(); -+ *tcp_stream = Some(stream); -+ } -+ -+ Ok(()) -+} -+ -+/// Establish TCP connection for client mode -+pub fn connect_tcp_client() -> Result<(), TdVmcallError> { -+ let addr = { -+ let tcp_addr = TCP_ADDRESS.lock(); -+ match tcp_addr.as_ref() { -+ Some(addr) => addr.clone(), -+ None => { -+ error!("TCP address not configured. Please set address before connecting."); -+ return Err(TdVmcallError::Other); -+ } -+ } -+ }; -+ -+ let stream = TcpStream::connect(&addr) -+ .map_err(|e| { -+ error!("Failed to connect to TCP server at {}: {}", addr, e); -+ TdVmcallError::Other -+ })?; -+ -+ // Store the stream globally for send/receive operations -+ { -+ let mut tcp_stream = TCP_STREAM.lock(); -+ *tcp_stream = Some(stream); -+ } -+ -+ Ok(()) -+} -+ -+/// Send raw data over TCP connection -+pub fn tcp_send_data(data: &[u8]) -> Result<(), TdVmcallError> { -+ -+ let mut stream_guard = TCP_STREAM.lock(); -+ let stream = stream_guard.as_mut().ok_or_else(|| { -+ error!("No TCP connection available for sending data"); -+ TdVmcallError::Other -+ })?; -+ -+ // Send data length first (4 bytes, little endian) -+ let length = data.len() as u32; -+ let len_bytes = length.to_le_bytes(); -+ stream -+ .write_all(&len_bytes) -+ .map_err(|e| { -+ error!("Failed to write length header: {}", e); -+ TdVmcallError::Other -+ })?; -+ -+ // Send raw data -+ stream.write_all(data) -+ .map_err(|e| { -+ error!("Failed to write data payload: {}", e); -+ TdVmcallError::Other -+ })?; -+ -+ stream.flush() -+ .map_err(|e| { -+ error!("Failed to flush TCP stream: {}", e); -+ TdVmcallError::Other -+ })?; -+ -+ Ok(()) -+} -+ -+/// Receive raw data from TCP connection -+pub fn tcp_receive_data() -> Result, TdVmcallError> { -+ -+ let mut stream_guard = TCP_STREAM.lock(); -+ let stream = stream_guard.as_mut().ok_or_else(|| { -+ error!("No TCP connection available for receiving data"); -+ TdVmcallError::Other -+ })?; -+ -+ // Read data length first (4 bytes, little endian) -+ let mut length_bytes = [0u8; 4]; -+ stream -+ .read_exact(&mut length_bytes) -+ .map_err(|e| { -+ error!("Failed to read length header: {}", e); -+ TdVmcallError::Other -+ })?; -+ -+ let length = u32::from_le_bytes(length_bytes) as usize; -+ -+ // Read raw data -+ let mut buffer = vec![0u8; length]; -+ stream -+ .read_exact(&mut buffer) -+ .map_err(|e| { -+ error!("Failed to read data payload: {}", e); -+ TdVmcallError::Other -+ })?; -+ -+ Ok(buffer) -+} -+ -+/// Helper function to parse TDX buffer format -+fn parse_tdx_buffer(buffer: &[u8]) -> (u32, u32, &[u8]) { -+ if buffer.len() < 8 { -+ return (0, 0, &[]); -+ } -+ -+ let status = u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]); -+ let length = u32::from_le_bytes([buffer[4], buffer[5], buffer[6], buffer[7]]); -+ let max_payload_len = (buffer.len() - 8).min(length as usize); -+ let payload = &buffer[8..8 + max_payload_len]; -+ -+ (status, length, payload) -+} -+ -+/// Helper function to format TDX buffer format -+fn format_tdx_buffer(buffer: &mut [u8], status: u32, payload: &[u8]) { -+ if buffer.len() < 8 { -+ return; -+ } -+ -+ // Compute how much we can actually copy into the caller-provided buffer. -+ let copy_len = (buffer.len() - 8).min(payload.len()); -+ -+ if copy_len < payload.len() { -+ error!( -+ "TDX buffer payload truncated: have space={} wanted={}", -+ buffer.len() - 8, -+ payload.len() -+ ); -+ } -+ -+ // Write status and the ACTUAL length we copied to avoid consumers overrunning buffers. -+ let status_bytes = status.to_le_bytes(); -+ let length_bytes = (copy_len as u32).to_le_bytes(); -+ -+ buffer[0..4].copy_from_slice(&status_bytes); -+ buffer[4..8].copy_from_slice(&length_bytes); -+ -+ if copy_len > 0 { -+ buffer[8..8 + copy_len].copy_from_slice(&payload[..copy_len]); -+ } -+} -+ -+/// TCP emulation for tdvmcall_migtd_send -+pub fn tdvmcall_migtd_send_sync( -+ _mig_request_id: u64, -+ data_buffer: &mut [u8], -+ interrupt: u8, -+) -> Result<(), TdVmcallError> { -+ -+ // Parse TDX buffer format to extract payload -+ let (_status, _length, payload) = parse_tdx_buffer(data_buffer); -+ -+ // Send payload over TCP -+ tcp_send_data(payload)?; -+ -+ // Update buffer to indicate success (status = 1, no payload response for send) -+ format_tdx_buffer(data_buffer, 1, &[]); -+ -+ // Trigger the registered interrupt callback to emulate VMM signaling -+ intr::trigger(interrupt); -+ Ok(()) -+} -+ -+/// TCP emulation for tdvmcall_migtd_receive -+pub fn tdvmcall_migtd_receive_sync( -+ _mig_request_id: u64, -+ data_buffer: &mut [u8], -+ interrupt: u8, -+) -> Result<(), TdVmcallError> { -+ -+ // Receive payload over TCP -+ let received_payload = tcp_receive_data()?; -+ -+ // Format response into TDX buffer (status = 1 for success) -+ format_tdx_buffer(data_buffer, 1, &received_payload); -+ -+ // Trigger the registered interrupt callback to emulate VMM signaling -+ intr::trigger(interrupt); -+ Ok(()) -+} -+ -+/// TCP emulation for tdvmcall_migtd_waitforrequest -+pub fn tdvmcall_migtd_waitforrequest( -+ data_buffer: &mut [u8], -+ interrupt: u8, -+) -> Result<(), TdVmcallError> { -+ -+ // data_buffer is a VmcallServiceResponse buffer prepared by caller. -+ // We must fill the response data area with ServiceMigWaitForReqResponse (vmcall-raw layout). -+ // Layout (little endian): -+ // offset 0: data_status u32 (1 = success) -+ // offset 4: request_type u32 (0) -+ // offset 8: mig_request_id u64 -+ // offset 16: migration_source u8 -+ // offset 17..24: reserved [7] = 0 -+ // offset 24..56: target_td_uuid [u64;4] -+ // offset 56..64: binding_handle u64 -+ const HEADER_LEN: usize = 24; // VmcallServiceResponse header size -+ if data_buffer.len() < HEADER_LEN + 64 { -+ error!( -+ "waitforrequest buffer too small: have={} need={}", -+ data_buffer.len(), -+ HEADER_LEN + 64 -+ ); -+ return Err(TdVmcallError::Other); -+ } -+ -+ // Take the emulated request info; if none, do not signal and let caller poll again -+ let maybe_req = { -+ let mut g = MIG_REQUEST.lock(); -+ g.take() -+ }; -+ -+ if let Some(st) = maybe_req { -+ let resp = &mut data_buffer[HEADER_LEN..HEADER_LEN + 64]; -+ // data_status = 1 -+ resp[0..4].copy_from_slice(&1u32.to_le_bytes()); -+ // request_type = 0 -+ resp[4..8].copy_from_slice(&0u32.to_le_bytes()); -+ // mig_request_id -+ resp[8..16].copy_from_slice(&st.request_id.to_le_bytes()); -+ // migration_source -+ resp[16] = st.migration_source; -+ // reserved -+ for b in &mut resp[17..24] { -+ *b = 0; -+ } -+ // target_td_uuid [u64;4] -+ let mut off = 24usize; -+ for v in st.target_td_uuid.iter() { -+ resp[off..off + 8].copy_from_slice(&v.to_le_bytes()); -+ off += 8; -+ } -+ // binding_handle -+ resp[56..64].copy_from_slice(&st.binding_handle.to_le_bytes()); -+ -+ // Signal completion via interrupt -+ intr::trigger(interrupt); -+ Ok(()) -+ } else { -+ // No pending request yet; do not signal. Caller will poll again. -+ Ok(()) -+ } -+} -+ -+/// TCP emulation for tdvmcall_migtd_reportstatus -+pub fn tdvmcall_migtd_reportstatus( -+ mig_request_id: u64, -+ pre_migration_status: u8, -+ data_buffer: &mut [u8], -+ interrupt: u8, -+) -> Result<(), TdVmcallError> { -+ log::info!( -+ "tdvmcall_migtd_reportstatus: request_id={} status={} interrupt=0x{:02x}", -+ mig_request_id, pre_migration_status, interrupt -+ ); -+ -+ // Parse current buffer data (we don't use the payload in status report) -+ let (_status, _length, _payload) = parse_tdx_buffer(data_buffer); -+ -+ // For now, we'll simulate a successful status report -+ // In a real implementation, this could send status over TCP if needed -+ -+ // Update buffer with success status -+ format_tdx_buffer(data_buffer, 1, &[]); // Status 1 = success -+ -+ // Emulate VMM signaling back to the TD that reportstatus completed -+ log::info!("tdvmcall_migtd_reportstatus: triggering interrupt 0x{:02x}", interrupt); -+ intr::trigger(interrupt); -+ Ok(()) -+} -+ -+/// Emulation for TDG.SERVTD.RD: read a metadata field of a target TD -+pub fn tdcall_servtd_rd( -+ binding_handle: u64, -+ field_identifier: u64, -+ target_td_uuid: &[u64], -+) -> Result { -+ if target_td_uuid.len() != 4 { -+ return Err(TdCallError::TdxExitInvalidParameters); -+ } -+ -+ let key = ( -+ binding_handle, -+ [ -+ target_td_uuid[0], -+ target_td_uuid[1], -+ target_td_uuid[2], -+ target_td_uuid[3], -+ ], -+ field_identifier, -+ ); -+ let val = MSK_FIELDS.lock().get(&key).copied().unwrap_or(0); -+ warn!( -+ "AzCVMEmu: tdcall_servtd_rd emulated: bh=0x{:x} field=0x{:x} uuid=[{:x},{:x},{:x},{:x}] => 0x{:x}", -+ binding_handle, field_identifier, key.1[0], key.1[1], key.1[2], key.1[3], val -+ ); -+ Ok(ServtdRWResult { content: val, uuid: key.1 }) -+} -+ -+/// Emulation for TDG.SERVTD.WR: write a metadata field of a target TD -+pub fn tdcall_servtd_wr( -+ binding_handle: u64, -+ field_identifier: u64, -+ data: u64, -+ target_td_uuid: &[u64], -+) -> Result { -+ if target_td_uuid.len() != 4 { -+ return Err(TdCallError::TdxExitInvalidParameters); -+ } -+ -+ let key = ( -+ binding_handle, -+ [ -+ target_td_uuid[0], -+ target_td_uuid[1], -+ target_td_uuid[2], -+ target_td_uuid[3], -+ ], -+ field_identifier, -+ ); -+ warn!( -+ "AzCVMEmu: tdcall_servtd_wr emulated: bh=0x{:x} field=0x{:x} uuid=[{:x},{:x},{:x},{:x}] <= 0x{:x}", -+ binding_handle, field_identifier, key.1[0], key.1[1], key.1[2], key.1[3], data -+ ); -+ MSK_FIELDS.lock().insert(key, data); -+ Ok(ServtdRWResult { content: data, uuid: key.1 }) -+} -+ -+/// Emulation for TDG.SYS.RD: read a global-scope metadata field -+pub fn tdcall_sys_rd(field_identifier: u64) -> core::result::Result<(u64, u64), TdCallError> { -+ // If a value was previously written via tdcall_sys_wr, return it. -+ if let Some(v) = SYS_FIELDS.lock().get(&field_identifier).copied() { -+ warn!( -+ "AzCVMEmu: tdcall_sys_rd emulated (stored): field=0x{:x} => 0x{:x}", -+ field_identifier, v -+ ); -+ return Ok((field_identifier, v)); -+ } -+ -+ // Provide sane defaults for min/max import/export versions; others return 0. -+ // Caller expects (rdx=field_identifier, r8=value). -+ const DEFAULT_MIN_VER: u64 = 1; -+ const DEFAULT_MAX_VER: u64 = 1; -+ let val = match field_identifier & 0xF { -+ 1 | 3 => DEFAULT_MIN_VER, -+ 2 | 4 => DEFAULT_MAX_VER, -+ _ => 0, -+ }; -+ warn!( -+ "AzCVMEmu: tdcall_sys_rd emulated (default): field=0x{:x} => 0x{:x}", -+ field_identifier, val -+ ); -+ Ok((field_identifier, val)) -+} -+ -+/// Emulation for TDG.SYS.WR: write a global-scope metadata field -+pub fn tdcall_sys_wr(field_identifier: u64, value: u64) -> core::result::Result<(), TdCallError> { -+ warn!( -+ "AzCVMEmu: tdcall_sys_wr emulated: field=0x{:x} <= 0x{:x}", -+ field_identifier, value -+ ); -+ SYS_FIELDS.lock().insert(field_identifier, value); -+ Ok(()) -+} -+ -+/// Emulation for TDG.VP.VMCALL: Generate TD-Quote using vTPM -+/// This mimics the exact API signature of tdx_tdcall::tdx::tdvmcall_get_quote -+pub fn tdvmcall_get_quote(buffer: &mut [u8]) -> Result<(), original_tdx_tdcall::TdVmcallError> { -+ use original_tdx_tdcall::TdVmcallError; -+ -+ log::info!("AzCVMEmu: tdvmcall_get_quote emulated using vTPM interface"); -+ -+ // TDX GHCI GetQuote buffer format: -+ // Offset 0-7: Version (u64, filled by TD) -+ // Offset 8-15: Status (u64, filled by VMM) - 0=success, 0xFFFFFFFFFFFFFFFF=in_flight -+ // Offset 16-23: TDREPORT length (u64, filled by TD) -+ // Offset 24-31: Quote buffer length (u64, filled by TD) -+ // Offset 32+: TDREPORT data (filled by TD) -+ // After TDREPORT: Quote data (filled by VMM) -+ -+ if buffer.len() < 32 { -+ error!("GetQuote buffer too small: need at least 32 bytes for header"); -+ return Err(TdVmcallError::VmcallOperandInvalid); -+ } -+ -+ // Read the TDREPORT length from the buffer -+ let tdreport_length = u64::from_le_bytes([ -+ buffer[16], buffer[17], buffer[18], buffer[19], -+ buffer[20], buffer[21], buffer[22], buffer[23], -+ ]) as usize; -+ -+ if tdreport_length == 0 || buffer.len() < 32 + tdreport_length { -+ error!("GetQuote buffer invalid: tdreport_length={} buffer_len={}", tdreport_length, buffer.len()); -+ return Err(TdVmcallError::VmcallOperandInvalid); -+ } -+ -+ // Extract the TDREPORT data (which contains the report data we need) -+ let tdreport_data = &buffer[32..32 + tdreport_length]; -+ -+ // For TD report, we typically use the first 48 bytes as report data -+ // In a real TDREPORT, the report data is at a specific offset -+ // For simplicity, we'll use the first 48 bytes or pad with zeros if shorter -+ let mut report_data = [0u8; 48]; -+ let copy_len = core::cmp::min(48, tdreport_data.len()); -+ report_data[..copy_len].copy_from_slice(&tdreport_data[..copy_len]); -+ -+ // Use the existing emulated quote generation -+ let quote = match crate::tdreport_emu::get_quote_emulated(&report_data) { -+ Ok(quote) => quote, -+ Err(e) => { -+ error!("Failed to generate quote in AzCVMEmu mode: {:?}", e); -+ // Set status to error -+ let error_status = 0x8000000000000000u64; // GET_QUOTE_ERROR -+ let status_bytes = error_status.to_le_bytes(); -+ buffer[8..16].copy_from_slice(&status_bytes); -+ return Err(TdVmcallError::Other); -+ } -+ }; -+ -+ // Check if there's enough space after TDREPORT for the quote -+ let quote_start_offset = 32 + tdreport_length; -+ if buffer.len() < quote_start_offset + quote.len() { -+ error!("GetQuote buffer too small for quote: need {} bytes, have {}", -+ quote_start_offset + quote.len(), buffer.len()); -+ // Set status to error -+ let error_status = 0x8000000000000000u64; // GET_QUOTE_ERROR -+ let status_bytes = error_status.to_le_bytes(); -+ buffer[8..16].copy_from_slice(&status_bytes); -+ return Err(TdVmcallError::VmcallOperandInvalid); -+ } -+ -+ // Write the generated quote after the TDREPORT -+ buffer[quote_start_offset..quote_start_offset + quote.len()].copy_from_slice("e); -+ -+ // Update the Quote buffer length field -+ let quote_length_bytes = (quote.len() as u64).to_le_bytes(); -+ buffer[24..32].copy_from_slice("e_length_bytes); -+ -+ // Set status to success (0) -+ let success_status = 0u64; -+ let status_bytes = success_status.to_le_bytes(); -+ buffer[8..16].copy_from_slice(&status_bytes); -+ -+ log::info!("AzCVMEmu: tdvmcall_get_quote completed successfully, quote size: {}", quote.len()); -+ Ok(()) -+} -+ -+/// Emulation for TDG.MR.EXTEND: extend a measurement into an RTMR -+/// In AzCVMEmu mode, we simulate this operation by logging it -+pub fn tdcall_extend_rtmr(digest: &original_tdx_tdcall::tdx::TdxDigest, mr_index: u32) -> Result<(), TdCallError> { -+ log::info!("AzCVMEmu: tdcall_extend_rtmr emulated - mr_index: {}, digest: {:02x?}", -+ mr_index, &digest.data[..8]); // Log first 8 bytes of digest -+ -+ // In a real implementation, this would extend the RTMR with the digest -+ // For emulation, we just simulate success -+ // The digest would be combined with the current RTMR value using SHA384 -+ -+ // Validate mr_index (RTMRs are typically 0-3) -+ if mr_index > 3 { -+ log::warn!("AzCVMEmu: Invalid RTMR index {} in tdcall_extend_rtmr", mr_index); -+ return Err(TdCallError::TdxExitInvalidParameters); -+ } -+ -+ log::debug!("AzCVMEmu: Successfully emulated RTMR {} extension", mr_index); -+ Ok(()) -+} -diff --git a/doc/AzCVMEmu.md b/doc/AzCVMEmu.md -new file mode 100644 -index 0000000..b6af11c ---- /dev/null -+++ b/doc/AzCVMEmu.md -@@ -0,0 +1,165 @@ -+### Build for Azure CVM Emulation (AzCVMEmu) -+ -+For development and testing MigTD core logic e2e flows, including RATLS with TDX Quote generation/verification and policy enforcement, you can build MigTD with emulation support as a standard Rust application. The Rust application can run within an Azure TDX CVM. Emulation implementation of the TDShim and tdcall interfaces are located under `deps/td-shim-AzCVMEmu`. MigTD Quote is emulated as TDX Quote of the Azure TDX CVM virtual FW layer. Code changes under `src` directory are kept to a minimum, mostly consisting of feature gates to select emulation layer or the real tds-shim layer, with several exceptions: -+ -+- Added `src/migtd/src/bin/migtd/cvmemu.rs` to handle emulation layer initialization and command-line processing. -+- As the RTMR extension is emulated as a no-op, the eventlog integrity check against RTMR is bypassed. -+- As the TDX Quote of Azure TDX CVM virtual FW constructs the REPORTDATA field of the Quote differently, the RATLS certificate public-key check against REPORTDATA is bypassed. -+- The crypto crate's `TlsTimerProvider` code is changed to return a fixed `current_time` timestamp to avoid invoking RTC access (a privileged instruction), which is not supported when building MigTD as a standard Rust application. -+- Added a script to patch libservtd-attest lib to link with the std runtime in AZCVMEmu build -+ -+**Note:** The `AzCVMEmu` feature only works with the `vmcall-raw` transport feature. When building with `AzCVMEmu`, the `main` and `vmcall-raw` features are enabled by default. You do not need to include them explicitly in the `--features` list. -+ -+**Production build** (requires Azure CVM + TPM2‑TSS): -+``` -+cargo build --no-default-features --features "AzCVMEmu" --bin migtd -+``` -+ -+**Test build** (development/testing - no TDX/Azure CVM required): -+``` -+cargo build --no-default-features --features "AzCVMEmu,test_disable_ra_and_accept_all" --bin migtd -+``` -+ -+**⚠️ Warning**: The `test_disable_ra_and_accept_all` feature bypasses remote attestation entirely and uses mock TD reports/quotes. This allows emulation mode MigTD to run in non-TDX, non-Azure CVM environments but will not cover MigTD code's TDX quote generation and verification flow. -+ -+This builds the `migtd` binary and required dependencies. -+ -+This enables MigTD to run as a standard command-line application with: -+- Standard library support (std) -+- File-based configuration for policy and root CA data -+- TCP transport for source/destination communication -+- Command-line argument parsing with help and error handling -+ -+#### Running MigTD in AzCVMEmu Mode -+ -+ -+Prerequisites: -+- [Azure v6 TDX CVM](https://learn.microsoft.com/en-us/azure/virtual-machines/sizes/general-purpose/dcesv6-series?tabs=sizebasic), running Ubuntu 24.04 or 22.04 (for production builds) -+- For testing with `test_disable_ra_and_accept_all` feature: any Linux system with Rust toolchain (no TDX/Azure CVM required) -+- TPM2‑TSS runtime is typically required at runtime because AzCVMEmu uses `az-tdx-vtpm`, which initializes TPM via `tss-esapi` by default. -+ - Ubuntu 24.04 minimal runtime packages: -+ - `libtss2-esys` (e.g., `libtss2-esys-3.0.2-0t64`) -+ - `libtss2-tcti-device0` (for `/dev/tpmrm0` access) -+ - Optional: `tpm2-tools` (debug/inspection), other TCTIs like `libtss2-tcti-mssim0`. -+ - Build-time: if build errors mention missing TSS2 headers, install `libtss2-dev`. -+ - The runner script auto-sets `TSS2_TCTI=device:/dev/tpmrm0` when the device exists and may enable sudo if permissions are insufficient. -+ - **Note**: When using `test_disable_ra_and_accept_all` feature, TPM2‑TSS is **not required** as mock TD reports and quotes are used instead of real TPM operations. -+ -+Ubuntu 24.04 quick install (example): -+ -+```bash -+sudo apt-get update -+sudo apt-get install -y libtss2-esys libtss2-tcti-device0 tpm2-tools -+``` -+ -+ -+**Using the migtdemu.sh script (recommended):** -+ -+The easiest way to run MigTD in AzCVMEmu mode is using the provided `migtdemu.sh` script, which automatically builds and runs MigTD with proper environment setup: -+ -+```bash -+# Display help -+./migtdemu.sh --help -+ -+# Build release and run as source (default) -+./migtdemu.sh -+ -+# Build debug and run as destination -+./migtdemu.sh --debug --role destination -+ -+# Run with custom configuration -+./migtdemu.sh --role source --request-id 42 --dest-ip 192.168.1.100 --dest-port 8002 -+ -+# Skip RA mode (no TDX/Azure CVM/TPM required) -+./migtdemu.sh --skip-ra --role source -+ -+# Skip RA mode with both source and destination -+./migtdemu.sh --skip-ra --both -+``` -+ -+Script capabilities at a glance: -+- Builds MigTD with `--no-default-features --features AzCVMEmu` in the selected mode (debug/release). -+- With `--skip-ra` flag: Builds with `--features "AzCVMEmu,test_disable_ra_and_accept_all"` for mock attestation. -+- Validates and sets required env vars: `MIGTD_POLICY_FILE` and `MIGTD_ROOT_CA_FILE`. -+- Auto-sets `RUST_BACKTRACE` (1) and `RUST_LOG` (debug in debug builds, info in release) unless already set. -+- If `/dev/tpmrm0` (or TPM2-ABRMD socket) is present and permissions are insufficient, it automatically enables sudo even if `--no-sudo` is passed. -+- Exports `TSS2_TCTI=device:/dev/tpmrm0` when the device exists, to help TPM2-TSS. -+- Single-role mode: runs just source or destination. -+- `--both`: starts destination in the background, waits for it to listen, then runs source in the foreground; destination logs go to `dest.out.log` and are tailed on failure. -+ -+Supported options: -+- `-r, --role ROLE` source | destination (default: source) -+- `-i, --request-id ID` migration request ID (default: 1) -+- `-d, --dest-ip IP` destination IP (default: 127.0.0.1) -+- `-p, --dest-port PORT` destination port (default: 8001) -+- `--policy-file FILE` policy file path (default: config/policy.json) -+- `--root-ca-file FILE` root CA file path (default: config/Intel_SGX_Provisioning_Certification_RootCA.cer) -+- `--debug | --release` build mode (default: release) -+- `--skip-ra` skip remote attestation (uses mock TD reports/quotes for non-TDX environments) -+- `--both` orchestrate destination then source on localhost -+- `--no-sudo` do not use sudo unless forced by TPM permissions -+- `-h, --help` show script help -+ -+What the script prints/shows: -+- Effective configuration (role, request-id, files, dest ip:port, sudo usage). -+- The exact command it will run (including env vars); useful for reproducing manual runs. -+- In `--both` mode, it prints destination PID and log path `dest.out.log`. -+ -+**Example usage with migtdemu.sh:** -+```bash -+# Terminal 1: Start destination MigTD in release mode -+./migtdemu.sh --role destination --request-id 42 -+ -+# Terminal 2: Start source MigTD connecting to the destination -+./migtdemu.sh --role source --request-id 42 --dest-ip 127.0.0.1 --dest-port 8001 -+ -+# Test mode examples (no Azure CVM/TPM required): -+# Terminal 1: Start destination MigTD in skip RA mode -+./migtdemu.sh --skip-ra --role destination --request-id 42 -+ -+# Terminal 2: Start source MigTD in skip RA mode -+./migtdemu.sh --skip-ra --role source --request-id 42 --dest-ip 127.0.0.1 --dest-port 8001 -+ -+# Or run both on same machine with skip RA mode: -+./migtdemu.sh --skip-ra --both --request-id 42 -+ -+# Debug mode example -+./migtdemu.sh --debug --role destination --request-id 123 -+ -+# Or orchestrate both on localhost (destination then source) -+./migtdemu.sh --both --request-id 77 -+``` -+ -+**Manual execution:** -+ -+If you prefer to run MigTD manually, you must first set the required environment variables: -+ -+```bash -+export MIGTD_POLICY_FILE="/path/to/your/policy.json" -+export MIGTD_ROOT_CA_FILE="/path/to/your/root_ca.cer" -+``` -+ -+Both files must exist at the specified paths. The program will exit with an error if either environment variable is missing or if the files cannot be found. vTPM access may require sudo: if TPM devices (e.g., /dev/tpmrm0) are present and permissions are insufficient, run with sudo or set `TSS2_TCTI` accordingly. The `migtdemu.sh` script auto-enables sudo when needed. -+ -+Run the application: -+ -+```bash -+# Display help information -+./target/release/migtd -h -+``` -+ -+Direct run examples (no script): -+- Destination (release, with sudo expected when TPM present): -+ sudo env MIGTD_POLICY_FILE=/path/to/policy.json MIGTD_ROOT_CA_FILE=/path/to/root_ca.cer RUST_LOG=info ./target/release/migtd --role destination --request-id 42 -+- Source (debug): -+ MIGTD_POLICY_FILE=/path/to/policy.json MIGTD_ROOT_CA_FILE=/path/to/root_ca.cer RUST_LOG=debug ./target/debug/migtd --role source --request-id 42 --dest-ip 127.0.0.1 --dest-port 8001 -+ -+**Built-in command-line options (from `./migtd -h`):** -+- `--request-id, -r ID`: Set migration request ID (default: 1) -+- `--role, -m ROLE`: Set role as 'source' or 'destination' (default: source) -+- `--uuid, -u U1 U2 U3 U4`: Set target TD UUID as four integers (default: 1 2 3 4) -+- `--binding, -b HANDLE`: Set binding handle as hex or decimal (default: 0x1234) -+- `--dest-ip, -d IP`: Set destination IP address for connection (default: 127.0.0.1) -+- `--dest-port, -t PORT`: Set destination port for connection (default: 8001) -+- `--help, -h`: Show help message -+ -diff --git a/migtdemu.sh b/migtdemu.sh -new file mode 100755 -index 0000000..788aa65 ---- /dev/null -+++ b/migtdemu.sh -@@ -0,0 +1,457 @@ -+#!/bin/bash -+ -+# MigTD AzCVMEmu Runner Script -+# This script builds and runs MigTD in AzCVMEmu mode. It can run one side -+# (source or destination) or orchestrate both on localhost. -+ -+set -e # Exit on any error -+ -+# Enable core dumps to help diagnose crashes (best-effort) -+ulimit -c unlimited || true -+ -+# Default configuration -+DEFAULT_POLICY_FILE="./config/policy.json" -+DEFAULT_ROOT_CA_FILE="./config/Intel_SGX_Provisioning_Certification_RootCA.cer" -+DEFAULT_ROLE="source" -+DEFAULT_REQUEST_ID="1" -+DEFAULT_DEST_IP="127.0.0.1" -+DEFAULT_DEST_PORT="8001" -+DEFAULT_BUILD_MODE="release" -+USE_SUDO=true -+RUN_BOTH=false -+SKIP_RA=false -+DEFAULT_RUST_BACKTRACE="1" -+# Default RUST_LOG: verbose in debug, info in release; can be overridden by env -+DEFAULT_RUST_LOG_DEBUG="debug" -+DEFAULT_RUST_LOG_RELEASE="info" -+ -+# Colors for output -+RED='\033[0;31m' -+GREEN='\033[0;32m' -+YELLOW='\033[1;33m' -+BLUE='\033[0;34m' -+NC='\033[0m' # No Color -+ -+# Function to display usage -+show_usage() { -+ echo -e "${BLUE}MigTD AzCVMEmu Runner Script${NC}" -+ echo -+ echo "Usage: $0 [OPTIONS]" -+ echo -+ echo "Options:" -+ echo " -r, --role ROLE Set role as 'source' or 'destination' (default: source)" -+ echo " -i, --request-id ID Set migration request ID (default: 1)" -+ echo " -d, --dest-ip IP Set destination IP address (default: 127.0.0.1)" -+ echo " -p, --dest-port PORT Set destination port (default: 8001)" -+ echo " --policy-file FILE Set policy file path (default: config/policy.json)" -+ echo " --root-ca-file FILE Set root CA file path (default: config/Intel_SGX_Provisioning_Certification_RootCA.cer)" -+ echo " --debug Build in debug mode (default: release)" -+ echo " --release Build in release mode (default)" -+ echo " --skip-ra Skip remote attestation (uses mock TD reports/quotes for non-TDX environments)" -+ echo " --both Start destination first, then source (same host)" -+ echo " --no-sudo Run without sudo (useful for local testing)" -+ echo " --log-level LEVEL Set Rust log level (trace, debug, info, warn, error) (default: debug for debug builds, info for release builds)" -+ echo " -h, --help Show this help message" -+ echo -+ echo "Notes:" -+ echo " - TPM2TSS flows often require access to /dev/tpmrm0 or tpm2-abrmd." -+ echo " If those devices are present and you lack permissions, this script will" -+ echo " automatically enable sudo even if --no-sudo is specified." -+ echo " - Skip RA mode (--skip-ra) disables remote attestation and uses mock TD reports/quotes," -+ echo " allowing MigTD to run in non-TDX, non-Azure CVM environments without TPM2-TSS dependencies." -+ echo " This is useful for development and testing on any Linux system." -+ echo -+ echo "Examples:" -+ echo " $0 # Build release and run as source with defaults" -+ echo " $0 --role destination # Build release and run as destination" -+ echo " $0 --debug --role source # Build debug and run as source" -+ echo " $0 --release --role destination # Build release and run as destination" -+ echo " $0 --skip-ra --role source # Build with skip RA mode (no TDX/Azure CVM/TPM required)" -+ echo " $0 --skip-ra --both # Run both source and destination with skip RA mode" -+ echo " $0 --log-level debug --role source # Run with debug log level" -+ echo " $0 --log-level warn --release # Run with warn log level in release mode" -+} -+ -+# Function to check if file exists -+check_file() { -+ local file="$1" -+ local description="$2" -+ -+ if [[ ! -f "$file" ]]; then -+ echo -e "${RED}Error: $description file not found: $file${NC}" >&2 -+ echo -e "${YELLOW}Please ensure the file exists or specify a different path.${NC}" >&2 -+ exit 1 -+ fi -+} -+ -+# Detect TPM access needs and force sudo when the current user lacks permissions -+maybe_force_sudo_due_to_tpm() { -+ # Skip TPM checks in skip RA mode since it uses mock attestation -+ if [[ "$SKIP_RA" == true ]]; then -+ return 0 -+ fi -+ -+ # Only relevant if user requested no sudo explicitly -+ if [[ "$USE_SUDO" == false ]]; then -+ local need_sudo=false -+ # If TPM resource manager or TPM char devices exist, check perms -+ local devices=(/dev/tpmrm0 /dev/tpm0) -+ for dev in "${devices[@]}"; do -+ if [[ -e "$dev" ]]; then -+ # Require read and write access for typical TPM2TSS usage -+ if [[ ! -r "$dev" || ! -w "$dev" ]]; then -+ need_sudo=true -+ break -+ fi -+ fi -+ done -+ # Also check for tpm2-abrmd socket ownership if present -+ if [[ -S "/run/tpm2-abrmd/sessions/tss" && ! -w "/run/tpm2-abrmd/sessions/tss" ]]; then -+ need_sudo=true -+ fi -+ # If user not in 'tss' group and TPM exists, likely need sudo -+ if [[ -e /dev/tpmrm0 || -e /dev/tpm0 ]]; then -+ if ! id -nG "$USER" 2>/dev/null | grep -qw tss; then -+ # Only flip if we already detected a device and permissions may be constrained -+ need_sudo=true -+ fi -+ fi -+ -+ if [[ "$need_sudo" == true ]]; then -+ echo -e "${YELLOW}TPM2TSS detected and current user lacks sufficient permissions. Enabling sudo automatically.${NC}" -+ USE_SUDO=true -+ fi -+ fi -+} -+ -+# Function to build MigTD -+build_migtd() { -+ local build_mode="$1" -+ local skip_ra="$2" -+ -+ local features="AzCVMEmu" -+ if [[ "$skip_ra" == true ]]; then -+ features="AzCVMEmu,test_disable_ra_and_accept_all" -+ echo -e "${BLUE}Building MigTD in $build_mode mode with AzCVMEmu + skip RA features (mock attestation)...${NC}" -+ else -+ echo -e "${BLUE}Building MigTD in $build_mode mode with AzCVMEmu features...${NC}" -+ fi -+ -+ if [[ "$build_mode" == "debug" ]]; then -+ if ! cargo build --features "$features" --no-default-features; then -+ echo -e "${RED}Error: Failed to build MigTD in debug mode${NC}" >&2 -+ exit 1 -+ fi -+ else -+ if ! cargo build --release --features "$features" --no-default-features; then -+ echo -e "${RED}Error: Failed to build MigTD in release mode${NC}" >&2 -+ exit 1 -+ fi -+ fi -+ echo -e "${GREEN}Build completed successfully in $build_mode mode${NC}" -+} -+ -+# Parse command line arguments -+ROLE="$DEFAULT_ROLE" -+REQUEST_ID="$DEFAULT_REQUEST_ID" -+DEST_IP="$DEFAULT_DEST_IP" -+DEST_PORT="$DEFAULT_DEST_PORT" -+POLICY_FILE="$DEFAULT_POLICY_FILE" -+ROOT_CA_FILE="$DEFAULT_ROOT_CA_FILE" -+BUILD_MODE="$DEFAULT_BUILD_MODE" -+CUSTOM_LOG_LEVEL="" -+ -+while [[ $# -gt 0 ]]; do -+ case $1 in -+ -r|--role) -+ ROLE="$2" -+ shift 2 -+ ;; -+ -i|--request-id) -+ REQUEST_ID="$2" -+ shift 2 -+ ;; -+ -d|--dest-ip) -+ DEST_IP="$2" -+ shift 2 -+ ;; -+ -p|--dest-port) -+ DEST_PORT="$2" -+ shift 2 -+ ;; -+ --policy-file) -+ POLICY_FILE="$2" -+ shift 2 -+ ;; -+ --root-ca-file) -+ ROOT_CA_FILE="$2" -+ shift 2 -+ ;; -+ --debug) -+ BUILD_MODE="debug" -+ shift -+ ;; -+ --release) -+ BUILD_MODE="release" -+ shift -+ ;; -+ --skip-ra) -+ SKIP_RA=true -+ shift -+ ;; -+ --both) -+ RUN_BOTH=true -+ shift -+ ;; -+ --no-sudo) -+ USE_SUDO=false -+ shift -+ ;; -+ --log-level) -+ CUSTOM_LOG_LEVEL="$2" -+ shift 2 -+ ;; -+ --build) -+ # Keep for backward compatibility, but it's now always enabled -+ shift -+ ;; -+ -h|--help) -+ show_usage -+ exit 0 -+ ;; -+ *) -+ echo -e "${RED}Error: Unknown option $1${NC}" >&2 -+ echo "Use --help for usage information." -+ exit 1 -+ ;; -+ esac -+done -+ -+# Validate role (skip when running both) -+if [[ "$RUN_BOTH" != true ]]; then -+ if [[ "$ROLE" != "source" && "$ROLE" != "destination" ]]; then -+ echo -e "${RED}Error: Role must be 'source' or 'destination', got: $ROLE${NC}" >&2 -+ exit 1 -+ fi -+fi -+ -+# Change to MigTD directory -+cd "$(dirname "$0")" -+ -+# Always build MigTD -+build_migtd "$BUILD_MODE" "$SKIP_RA" -+ -+# Determine binary path based on build mode (unified migtd binary) -+if [[ "$BUILD_MODE" == "debug" ]]; then -+ MIGTD_BINARY="./target/debug/migtd" -+else -+ MIGTD_BINARY="./target/release/migtd" -+fi -+ -+# Check if configuration files exist -+check_file "$POLICY_FILE" "Policy" -+check_file "$ROOT_CA_FILE" "Root CA" -+ -+# Evaluate TPM access and elevate if necessary -+maybe_force_sudo_due_to_tpm -+ -+run_cmd() { -+ # Run a command with or without sudo, preserving the provided environment -+ # Usage: run_cmd VAR1=... VAR2=... -- [args...] -+ local env_kv=() -+ while [[ $# -gt 0 ]]; do -+ case $1 in -+ --) -+ shift -+ break -+ ;; -+ *=*) -+ env_kv+=("$1") -+ shift -+ ;; -+ *) -+ break -+ ;; -+ esac -+ done -+ if $USE_SUDO; then -+ sudo env "${env_kv[@]}" "$@" -+ else -+ env "${env_kv[@]}" "$@" -+ fi -+} -+ -+wait_for_port() { -+ local ip="$1" -+ local port="$2" -+ local timeout_sec="${3:-15}" -+ echo -e "${BLUE}Waiting for ${ip}:${port} to listen (timeout ${timeout_sec}s)...${NC}" -+ local start_ts=$(date +%s) -+ while true; do -+ # Prefer 'ss' if available -+ if command -v ss >/dev/null 2>&1; then -+ if ss -lnt "sport = :$port" | grep -q LISTEN; then -+ echo -e "${GREEN}Port ${port} is now listening.${NC}" -+ return 0 -+ fi -+ else -+ # Fallback: try bash TCP connect -+ (echo > "/dev/tcp/${ip}/${port}") >/dev/null 2>&1 && { -+ echo -e "${GREEN}Port ${port} is reachable.${NC}" -+ return 0 -+ } -+ fi -+ local now_ts=$(date +%s) -+ if (( now_ts - start_ts >= timeout_sec )); then -+ echo -e "${RED}Timeout waiting for ${ip}:${port}${NC}" >&2 -+ return 1 -+ fi -+ sleep 0.5 -+ done -+} -+ -+echo -e "${BLUE}Setting up environment variables...${NC}" -+ -+# Display configuration -+echo -e "${GREEN}Configuration:${NC}" -+echo " Build mode: $BUILD_MODE" -+if [[ "$SKIP_RA" == true ]]; then -+ echo " Skip RA mode: enabled (mock attestation, no TDX/Azure CVM/TPM required)" -+else -+ echo " Skip RA mode: disabled (requires TDX/Azure CVM/TPM for attestation)" -+fi -+if [[ "$RUN_BOTH" == true ]]; then -+ echo " Mode: both (destination then source)" -+else -+ echo " Role: $ROLE" -+fi -+echo " Request ID: $REQUEST_ID" -+echo " Policy file: $POLICY_FILE" -+echo " Root CA file: $ROOT_CA_FILE" -+echo " Use sudo: $USE_SUDO" -+ -+echo " Destination: ${DEST_IP}:${DEST_PORT}" -+ -+echo -+ -+# Prepare runtime env vars -+if [[ -z "$RUST_BACKTRACE" ]]; then -+ RUST_BACKTRACE="$DEFAULT_RUST_BACKTRACE" -+fi -+if [[ -z "$RUST_LOG" ]]; then -+ if [[ -n "$CUSTOM_LOG_LEVEL" ]]; then -+ RUST_LOG="$CUSTOM_LOG_LEVEL" -+ elif [[ "$BUILD_MODE" == "debug" ]]; then -+ RUST_LOG="$DEFAULT_RUST_LOG_DEBUG" -+ else -+ RUST_LOG="$DEFAULT_RUST_LOG_RELEASE" -+ fi -+fi -+ -+# Prefer TPM resource manager device for TPM2TSS if present -+TSS2_TCTI_AUTO="" -+if [[ "$SKIP_RA" != true && -e /dev/tpmrm0 ]]; then -+ TSS2_TCTI_AUTO="device:/dev/tpmrm0" -+fi -+ -+if [[ "$RUN_BOTH" == true ]]; then -+ echo -e "${BLUE}Starting destination in background...${NC}" -+ DEST_ARGS=("--role" "destination" "--request-id" "$REQUEST_ID") -+ # Start destination and redirect output -+ ( -+ set -x -+ if [[ -n "$TSS2_TCTI_AUTO" ]]; then -+ run_cmd "MIGTD_POLICY_FILE=$POLICY_FILE" "MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE" "RUST_BACKTRACE=$RUST_BACKTRACE" "RUST_LOG=$RUST_LOG" "TSS2_TCTI=$TSS2_TCTI_AUTO" -- "$MIGTD_BINARY" "${DEST_ARGS[@]}" -+ else -+ run_cmd "MIGTD_POLICY_FILE=$POLICY_FILE" "MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE" "RUST_BACKTRACE=$RUST_BACKTRACE" "RUST_LOG=$RUST_LOG" -- "$MIGTD_BINARY" "${DEST_ARGS[@]}" -+ fi -+ ) > dest.out.log 2>&1 & -+ DEST_PID=$! -+ echo -e "${GREEN}Destination started with PID ${DEST_PID}. Logs: dest.out.log${NC}" -+ -+ # Ensure destination is listening -+ if ! wait_for_port "$DEST_IP" "$DEST_PORT" 20; then -+ echo -e "${RED}Destination didn't start listening on ${DEST_IP}:${DEST_PORT}.${NC}" >&2 -+ echo -e "${YELLOW}Last 50 lines of dest.out.log:${NC}" -+ tail -n 50 dest.out.log || true -+ kill "$DEST_PID" >/dev/null 2>&1 || true -+ exit 1 -+ fi -+ -+ # Trap to cleanup background process on exit -+ trap 'echo -e "\n${YELLOW}Cleaning up destination process (PID ${DEST_PID})...${NC}"; if kill -0 ${DEST_PID} 2>/dev/null; then kill ${DEST_PID} >/dev/null 2>&1 || true; wait ${DEST_PID} 2>/dev/null || true; fi' EXIT -+ -+ echo -e "${BLUE}Starting source (foreground)...${NC}" -+ SRC_ARGS=( -+ "--role" "source" -+ "--request-id" "$REQUEST_ID" -+ "--dest-ip" "$DEST_IP" -+ "--dest-port" "$DEST_PORT" -+ ) -+ if [[ "$USE_SUDO" == true ]]; then SUDO_STR="sudo "; else SUDO_STR=""; fi -+ echo -e "${YELLOW}Command: ${SUDO_STR}MIGTD_POLICY_FILE=$POLICY_FILE MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE $MIGTD_BINARY ${SRC_ARGS[*]}${NC}" -+ echo -+ # Run source in foreground -+ if [[ "$USE_SUDO" == true ]]; then SUDO_STR="sudo "; else SUDO_STR=""; fi -+ if [[ -n "$TSS2_TCTI_AUTO" ]]; then -+ echo -e "${YELLOW}Command: ${SUDO_STR}MIGTD_POLICY_FILE=$POLICY_FILE MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE RUST_BACKTRACE=$RUST_BACKTRACE RUST_LOG=$RUST_LOG TSS2_TCTI=$TSS2_TCTI_AUTO $MIGTD_BINARY ${SRC_ARGS[*]}${NC}" -+ else -+ echo -e "${YELLOW}Command: ${SUDO_STR}MIGTD_POLICY_FILE=$POLICY_FILE MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE RUST_BACKTRACE=$RUST_BACKTRACE RUST_LOG=$RUST_LOG $MIGTD_BINARY ${SRC_ARGS[*]}${NC}" -+ fi -+ echo -+ # Run source in foreground; on failure, show last logs and exit non-zero -+ if [[ -n "$TSS2_TCTI_AUTO" ]]; then -+ run_cmd "MIGTD_POLICY_FILE=$POLICY_FILE" "MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE" "RUST_BACKTRACE=$RUST_BACKTRACE" "RUST_LOG=$RUST_LOG" "TSS2_TCTI=$TSS2_TCTI_AUTO" -- "$MIGTD_BINARY" "${SRC_ARGS[@]}" -+ SRC_EXIT_CODE=$? -+ else -+ run_cmd "MIGTD_POLICY_FILE=$POLICY_FILE" "MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE" "RUST_BACKTRACE=$RUST_BACKTRACE" "RUST_LOG=$RUST_LOG" -- "$MIGTD_BINARY" "${SRC_ARGS[@]}" -+ SRC_EXIT_CODE=$? -+ fi -+ echo -e "${BLUE}Source migtd exit code: $SRC_EXIT_CODE${NC}" -+ -+ # Check destination exit code before stopping it -+ if kill -0 "$DEST_PID" 2>/dev/null; then -+ echo -e "${BLUE}Destination is still running, stopping it...${NC}" -+ kill "$DEST_PID" >/dev/null 2>&1 || true -+ wait "$DEST_PID" 2>/dev/null || true -+ DEST_EXIT_CODE=$? -+ echo -e "${BLUE}Destination migtd exit code: $DEST_EXIT_CODE${NC}" -+ else -+ # Destination already exited, get its exit code -+ wait "$DEST_PID" 2>/dev/null || true -+ DEST_EXIT_CODE=$? -+ echo -e "${BLUE}Destination migtd exit code: $DEST_EXIT_CODE${NC}" -+ fi -+ -+ if [[ "$SRC_EXIT_CODE" -ne 0 ]]; then -+ echo -e "${RED}Source run failed. Last 100 lines of destination log:${NC}" -+ tail -n 100 dest.out.log || true -+ exit $SRC_EXIT_CODE -+ fi -+else -+ # Single role run -+ MIGTD_ARGS=( -+ "--role" "$ROLE" -+ "--request-id" "$REQUEST_ID" -+ ) -+ if [[ "$ROLE" == "source" ]]; then -+ MIGTD_ARGS+=("--dest-ip" "$DEST_IP" "--dest-port" "$DEST_PORT") -+ fi -+ echo -e "${BLUE}Starting MigTD in $ROLE mode...${NC}" -+ if [[ "$USE_SUDO" == true ]]; then SUDO_STR="sudo "; else SUDO_STR=""; fi -+ if [[ -n "$TSS2_TCTI_AUTO" ]]; then -+ echo -e "${YELLOW}Command: ${SUDO_STR}MIGTD_POLICY_FILE=$POLICY_FILE MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE RUST_BACKTRACE=$RUST_BACKTRACE RUST_LOG=$RUST_LOG TSS2_TCTI=$TSS2_TCTI_AUTO $MIGTD_BINARY ${MIGTD_ARGS[*]}${NC}" -+ else -+ echo -e "${YELLOW}Command: ${SUDO_STR}MIGTD_POLICY_FILE=$POLICY_FILE MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE RUST_BACKTRACE=$RUST_BACKTRACE RUST_LOG=$RUST_LOG $MIGTD_BINARY ${MIGTD_ARGS[*]}${NC}" -+ fi -+ echo -+ if [[ -n "$TSS2_TCTI_AUTO" ]]; then -+ run_cmd "MIGTD_POLICY_FILE=$POLICY_FILE" "MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE" "RUST_BACKTRACE=$RUST_BACKTRACE" "RUST_LOG=$RUST_LOG" "TSS2_TCTI=$TSS2_TCTI_AUTO" -- "$MIGTD_BINARY" "${MIGTD_ARGS[@]}" -+ EXIT_CODE=$? -+ else -+ run_cmd "MIGTD_POLICY_FILE=$POLICY_FILE" "MIGTD_ROOT_CA_FILE=$ROOT_CA_FILE" "RUST_BACKTRACE=$RUST_BACKTRACE" "RUST_LOG=$RUST_LOG" -- "$MIGTD_BINARY" "${MIGTD_ARGS[@]}" -+ EXIT_CODE=$? -+ fi -+ echo -e "${BLUE}MigTD exit code: $EXIT_CODE${NC}" -+ exit $EXIT_CODE -+fi -diff --git a/readme.md b/readme.md -index 3902ebd..a3500f6 100644 ---- a/readme.md -+++ b/readme.md -@@ -127,6 +127,14 @@ To generate IGVM format using vmcall-raw for the guest-host communication with l - cargo image --no-default-features --features vmcall-raw,stack-guard,main,test_disable_ra_and_accept_all,vmcall-interrupt --log-level info --image-format igvm - ``` - -+### Build for Azure CVM Emulation (AzCVMEmu) -+ -+To build MigTD as a standard Rust app that can run in Azure TDX CVM environment, for development and testing purpose: -+``` -+cargo build --no-default-features --features AzCVMEmu -+``` -+The detailed AzCVMEmu mode instructions can be found in `doc/AzCVMEmu.md`. -+ - ### Generate SERVTD_INFO_HASH - - `SERVTD_HASH_INFO` can be calculated based on a given MigTD image and a TD configuration such as -diff --git a/src/attestation/Cargo.toml b/src/attestation/Cargo.toml -index e855aef..fadd9e6 100644 ---- a/src/attestation/Cargo.toml -+++ b/src/attestation/Cargo.toml -@@ -13,6 +13,10 @@ spin = "0.9.2" - tdx-tdcall = { path = "../../deps/td-shim/tdx-tdcall"} - td-payload = { path = "../../deps/td-shim/td-payload", features = ["tdx"] } - -+# Use emulated tdx-tdcall for AzCVMEmu -+tdx-tdcall-emu = { path = "../../deps/td-shim-AzCVMEmu/tdx-tdcall", optional = true } -+ - [features] - default = [] - test = [] -+AzCVMEmu = ["tdx-tdcall-emu"] -diff --git a/src/attestation/build.rs b/src/attestation/build.rs -index 299d7b4..58d662e 100644 ---- a/src/attestation/build.rs -+++ b/src/attestation/build.rs -@@ -51,5 +51,21 @@ fn main() { - ); - - println!("cargo:rustc-link-search=native={}", search_dir); -+ -+ // Use different linking approach based on feature -+ #[cfg(feature = "AzCVMEmu")] -+ { -+ // Run the fixup script to create the modified library for AzCVMEmu -+ let script_path = crate_path.join("fixup-libservtd-attest-lib.sh"); -+ let status = Command::new("bash") -+ .arg(&script_path) -+ .current_dir(&crate_path) -+ .status() -+ .expect("failed to run fixup-libservtd-attest-lib.sh script!"); -+ assert!(status.success(), "failed to run fixup script: {status}"); -+ println!("cargo:rustc-link-arg=-lservtd_attest_app"); -+ println!("cargo:rustc-link-arg=-lcrypto"); -+ } -+ #[cfg(not(feature = "AzCVMEmu"))] - println!("cargo:rustc-link-lib=static=servtd_attest"); - } -diff --git a/src/attestation/fixup-libservtd-attest-lib.sh b/src/attestation/fixup-libservtd-attest-lib.sh -new file mode 100755 -index 0000000..62af35e ---- /dev/null -+++ b/src/attestation/fixup-libservtd-attest-lib.sh -@@ -0,0 +1,92 @@ -+#!/bin/bash -+ -+##============================================================================== -+## -+## Find libservtd_attest.a (there may be more than one) -+## -+##============================================================================== -+ -+targets="../../deps/linux-sgx/external/dcap_source/QuoteGeneration/quote_wrapper/servtd_attest/linux/libservtd_attest.a" -+ -+##============================================================================== -+## -+## Find tlibc library -+## -+##============================================================================== -+ -+tlibc_lib=$(find ../../deps/linux-sgx -name libtlibc.a) -+if [ ! -f "${tlibc_lib}" ]; then -+ echo "$0: tlibc lib not found" -+ exit 1; -+fi -+ -+##============================================================================== -+## -+## Find sgxssl library -+## -+##============================================================================== -+ -+sgxssl_lib=$(find ../../deps/linux-sgx -name libsgx_tsgxssl_crypto.a) -+if [ ! -f "${sgxssl_lib}" ]; then -+ echo "$0: sgxssl lib not found" -+ exit 1; -+fi -+ -+##============================================================================== -+## -+## Remove unwanted objects from servtd_attest archive. This deletes all objects -+## found in libsgx_tsgxssl_crypto.a from libservtd_attest.a. It also deletes -+## most objects found in libtlibc.a from libservtd_attest.a (a few objects are -+## spared, since tlibc introduces non-standard symbols, such as spinlocks and -+## various non-standard string functions). -+## -+##============================================================================== -+ -+for i in ${targets} -+do -+ lib="${i%.a}_app.a" -+ cp "${i}" "${lib}" -+ if [ "$?" != "0" ]; then -+ echo "$0: failed to copy ${i} to ${lib}" -+ exit 1; -+ fi -+ ar d ${lib} $(ar t ${tlibc_lib} | grep -v spinlock.o | grep -v memset | grep -v memcpy ) -+ ar d ${lib} $(ar t ${sgxssl_lib}) -+ echo "Created ${lib}" -+done -+ -+##============================================================================== -+## -+## Add object with extra code to archive. The errno and heap related objects -+## were removed above so definitions are added here to compensate. -+## -+##============================================================================== -+ -+dir=$(mktemp -d) -+src=${dir}/libservtd_attest_extras.c -+obj=${dir}/libservtd_attest_extras.o -+ -+cat > ${src} < -+ -+int* __errno() -+{ -+ extern int* __errno_location(); -+ return __errno_location(); -+} -+ -+void* heap_base; -+size_t heap_size; -+END -+ -+gcc -c ${src} -o ${obj} -+if [ "$?" != "0" ]; then -+ echo "$0: compile failed: ${src}" -+ exit 1; -+fi -+ -+for i in ${targets} -+do -+ lib="${i%.a}_app.a" -+ ar r "${lib}" "${obj}" -+done -\ No newline at end of file -diff --git a/src/attestation/src/attest.rs b/src/attestation/src/attest.rs -index d3ed907..ee16c6c 100644 ---- a/src/attestation/src/attest.rs -+++ b/src/attestation/src/attest.rs -@@ -3,11 +3,15 @@ - // SPDX-License-Identifier: BSD-2-Clause-Patent - - use crate::{ -- binding::get_quote as get_quote_inner, binding::init_heap, binding::verify_quote_integrity, -- binding::AttestLibError, root_ca::ROOT_CA, Error, TD_VERIFIED_REPORT_SIZE, -+ binding::init_heap, binding::verify_quote_integrity, binding::AttestLibError, root_ca::ROOT_CA, -+ Error, TD_VERIFIED_REPORT_SIZE, - }; - use alloc::{vec, vec::Vec}; - use core::{alloc::Layout, ffi::c_void, ops::Range}; -+ -+#[cfg(not(feature = "AzCVMEmu"))] -+use crate::binding::get_quote as get_quote_inner; -+#[cfg(not(feature = "AzCVMEmu"))] - use tdx_tdcall::tdreport::*; - - const TD_QUOTE_SIZE: usize = 0x2000; -@@ -25,6 +29,7 @@ pub fn attest_init_heap() -> Option { - Some(ATTEST_HEAP_SIZE) - } - -+#[cfg(not(feature = "AzCVMEmu"))] - pub fn get_quote(td_report: &[u8]) -> Result, Error> { - let mut quote = vec![0u8; TD_QUOTE_SIZE]; - let mut quote_size = TD_QUOTE_SIZE as u32; -@@ -43,6 +48,68 @@ pub fn get_quote(td_report: &[u8]) -> Result, Error> { - Ok(quote) - } - -+#[cfg(feature = "AzCVMEmu")] -+pub fn get_quote(td_report: &[u8]) -> Result, Error> { -+ // Create a GetQuote buffer following TDX GHCI format -+ // This approach works for both AzCVMEmu and normal modes -+ let tdreport_length = td_report.len(); -+ let buffer_size = 32 + tdreport_length + TD_QUOTE_SIZE; // Header + TDReport + space for quote -+ let mut buffer = vec![0u8; buffer_size]; -+ -+ // Fill GetQuote buffer header -+ // Version (offset 0-7) -+ let version = 1u64.to_le_bytes(); -+ buffer[0..8].copy_from_slice(&version); -+ -+ // Status will be filled by VMM (offset 8-15) -+ // Initially set to "in flight" -+ let status = 0xFFFFFFFFFFFFFFFFu64.to_le_bytes(); -+ buffer[8..16].copy_from_slice(&status); -+ -+ // TDREPORT length (offset 16-23) -+ let tdreport_len_bytes = (tdreport_length as u64).to_le_bytes(); -+ buffer[16..24].copy_from_slice(&tdreport_len_bytes); -+ -+ // Quote buffer length (offset 24-31) - will be updated by VMM -+ let quote_buf_len_bytes = (TD_QUOTE_SIZE as u64).to_le_bytes(); -+ buffer[24..32].copy_from_slice("e_buf_len_bytes); -+ -+ // Copy TDREPORT data (offset 32+) -+ buffer[32..32 + tdreport_length].copy_from_slice(td_report); -+ -+ // Call tdvmcall_get_quote with our emulated implementation -+ use tdx_tdcall_emu::tdx::tdvmcall_get_quote; -+ -+ if tdvmcall_get_quote(&mut buffer).is_err() { -+ return Err(Error::GetQuote); -+ } -+ -+ // Check status for success -+ let status = u64::from_le_bytes([ -+ buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], -+ buffer[15], -+ ]); -+ -+ if status != 0 { -+ return Err(Error::GetQuote); -+ } -+ -+ // Read quote length -+ let quote_length = u64::from_le_bytes([ -+ buffer[24], buffer[25], buffer[26], buffer[27], buffer[28], buffer[29], buffer[30], -+ buffer[31], -+ ]) as usize; -+ -+ // Extract quote data -+ let quote_start = 32 + tdreport_length; -+ if buffer.len() < quote_start + quote_length { -+ return Err(Error::GetQuote); -+ } -+ -+ let quote = buffer[quote_start..quote_start + quote_length].to_vec(); -+ Ok(quote) -+} -+ - pub fn verify_quote(quote: &[u8]) -> Result, Error> { - let mut td_report_verify = vec![0u8; TD_REPORT_VERIFY_SIZE]; - let mut report_verify_size = TD_REPORT_VERIFY_SIZE as u32; -diff --git a/src/attestation/src/collateral.rs b/src/attestation/src/collateral.rs -new file mode 100644 -index 0000000..25d8e8b ---- /dev/null -+++ b/src/attestation/src/collateral.rs -@@ -0,0 +1,1020 @@ -+// Copyright (c) 2022 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+// This module is only compiled for AzCVMEmu mode -+#![cfg(feature = "AzCVMEmu")] -+ -+use std::mem::size_of; -+use std::ptr; -+use std::sync::{Mutex, Once}; -+ -+/// Hardcoded collateral data that will be loaded into the global storage -+const HARDCODED_COLLATERAL: &[u8] = &[ -+ 0x03, 0x00, 0x00, 0x00, 0x71, 0x07, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x49, 0x0e, 0x00, 0x00, -+ 0x65, 0x07, 0x00, 0x00, 0xc4, 0x0b, 0x00, 0x00, 0x65, 0x07, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, -+ 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, -+ 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, -+ 0x6c, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x32, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, -+ 0x41, 0x4a, 0x56, 0x76, 0x58, 0x63, 0x32, 0x39, 0x47, 0x2b, 0x48, 0x70, 0x51, 0x45, 0x6e, 0x4a, -+ 0x31, 0x50, 0x51, 0x7a, 0x7a, 0x67, 0x46, 0x58, 0x43, 0x39, 0x35, 0x55, 0x4d, 0x41, 0x6f, 0x47, -+ 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x4d, 0x47, 0x67, -+ 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x45, 0x55, 0x6c, -+ 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, 0x48, 0x57, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, -+ 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, -+ 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x33, -+ 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, -+ 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, -+ 0x45, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, -+ 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x0a, 0x43, -+ 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x41, 0x65, 0x46, -+ 0x77, 0x30, 0x78, 0x4f, 0x44, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, -+ 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x7a, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, -+ 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x4d, 0x48, 0x41, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x0a, -+ 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x47, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, -+ 0x49, 0x46, 0x4e, 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x47, 0x78, 0x68, -+ 0x64, 0x47, 0x5a, 0x76, 0x63, 0x6d, 0x30, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, -+ 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, -+ 0x0a, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, -+ 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, -+ 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, -+ 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, -+ 0x78, 0x0a, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, -+ 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, -+ 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, 0x51, -+ 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x4e, 0x53, 0x42, 0x2f, 0x37, 0x74, 0x32, 0x31, 0x6c, 0x58, -+ 0x53, 0x4f, 0x0a, 0x32, 0x43, 0x75, 0x7a, 0x70, 0x78, 0x77, 0x37, 0x34, 0x65, 0x4a, 0x42, 0x37, -+ 0x32, 0x45, 0x79, 0x44, 0x47, 0x67, 0x57, 0x35, 0x72, 0x58, 0x43, 0x74, 0x78, 0x32, 0x74, 0x56, -+ 0x54, 0x4c, 0x71, 0x36, 0x68, 0x4b, 0x6b, 0x36, 0x7a, 0x2b, 0x55, 0x69, 0x52, 0x5a, 0x43, 0x6e, -+ 0x71, 0x52, 0x37, 0x70, 0x73, 0x4f, 0x76, 0x67, 0x71, 0x46, 0x65, 0x53, 0x78, 0x6c, 0x6d, 0x54, -+ 0x6c, 0x4a, 0x6c, 0x0a, 0x65, 0x54, 0x6d, 0x69, 0x32, 0x57, 0x59, 0x7a, 0x33, 0x71, 0x4f, 0x42, -+ 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, -+ 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, -+ 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, -+ 0x72, 0x44, 0x42, 0x53, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, -+ 0x4a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, -+ 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, -+ 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, -+ 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, -+ 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, -+ 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, -+ 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, -+ 0x51, 0x55, 0x6c, 0x57, 0x39, 0x64, 0x0a, 0x7a, 0x62, 0x30, 0x62, 0x34, 0x65, 0x6c, 0x41, 0x53, -+ 0x63, 0x6e, 0x55, 0x39, 0x44, 0x50, 0x4f, 0x41, 0x56, 0x63, 0x4c, 0x33, 0x6c, 0x51, 0x77, 0x44, -+ 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, -+ 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, -+ 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x0a, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, -+ 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, -+ 0x52, 0x77, 0x41, 0x77, 0x52, 0x41, 0x49, 0x67, 0x58, 0x73, 0x56, 0x6b, 0x69, 0x30, 0x77, 0x2b, -+ 0x69, 0x36, 0x56, 0x59, 0x47, 0x57, 0x33, 0x55, 0x46, 0x2f, 0x32, 0x32, 0x75, 0x61, 0x58, 0x65, -+ 0x30, 0x59, 0x4a, 0x44, 0x6a, 0x31, 0x55, 0x65, 0x0a, 0x6e, 0x41, 0x2b, 0x54, 0x6a, 0x44, 0x31, -+ 0x61, 0x69, 0x35, 0x63, 0x43, 0x49, 0x43, 0x59, 0x62, 0x31, 0x53, 0x41, 0x6d, 0x44, 0x35, 0x78, -+ 0x6b, 0x66, 0x54, 0x56, 0x70, 0x76, 0x6f, 0x34, 0x55, 0x6f, 0x79, 0x69, 0x53, 0x59, 0x78, 0x72, -+ 0x44, 0x57, 0x4c, 0x6d, 0x55, 0x52, 0x34, 0x43, 0x49, 0x39, 0x4e, 0x4b, 0x79, 0x66, 0x50, 0x4e, -+ 0x2b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, -+ 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, -+ 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, -+ 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6a, 0x7a, 0x43, 0x43, -+ 0x41, 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, 0x4d, -+ 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, 0x72, 0x39, 0x51, -+ 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, -+ 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, -+ 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, -+ 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, -+ 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, -+ 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, -+ 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, -+ 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, -+ 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, -+ 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, -+ 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4d, -+ 0x44, 0x55, 0x79, 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x55, 0x78, 0x4d, 0x46, 0x6f, 0x58, 0x44, -+ 0x54, 0x51, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, -+ 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, -+ 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, -+ 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, -+ 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, -+ 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x0a, 0x61, 0x57, 0x39, -+ 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, -+ 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, -+ 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, -+ 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x0a, 0x41, 0x6c, -+ 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, -+ 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, 0x51, -+ 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x43, 0x36, 0x6e, 0x45, 0x77, 0x4d, 0x44, 0x49, 0x59, 0x5a, -+ 0x4f, 0x6a, 0x2f, 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, 0x4b, 0x69, 0x37, 0x0a, 0x31, -+ 0x4f, 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, 0x4a, -+ 0x66, 0x56, 0x6e, 0x6b, 0x59, 0x34, 0x75, 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, 0x59, 0x4c, 0x30, -+ 0x4d, 0x78, 0x4f, 0x34, 0x6d, 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, 0x42, 0x61, 0x6c, 0x54, 0x56, -+ 0x59, 0x78, 0x46, 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, -+ 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, -+ 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, -+ 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, -+ 0x72, 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, -+ 0x0a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, -+ 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, -+ 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, -+ 0x6b, 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, -+ 0x30, 0x0a, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, -+ 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, -+ 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, -+ 0x51, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, -+ 0x53, 0x56, 0x0a, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x44, -+ 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, -+ 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, -+ 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, -+ 0x67, 0x59, 0x49, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, -+ 0x53, 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, 0x52, -+ 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4e, 0x6f, 0x6f, 0x77, 0x4c, 0x75, 0x50, 0x52, -+ 0x4c, 0x73, 0x57, 0x47, 0x66, 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, 0x58, 0x39, 0x34, 0x42, 0x67, -+ 0x77, 0x54, 0x77, 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, -+ 0x4d, 0x73, 0x2b, 0x58, 0x6f, 0x35, 0x6f, 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, 0x78, -+ 0x48, 0x52, 0x41, 0x76, 0x5a, 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, 0x63, 0x76, 0x71, 0x52, -+ 0x58, 0x61, 0x71, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, -+ 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, -+ 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x58, 0x35, 0x30, 0x39, -+ 0x20, 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x44, -+ 0x43, 0x42, 0x79, 0x41, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, -+ 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x6a, 0x42, 0x6f, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, -+ 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x43, -+ 0x42, 0x54, 0x52, 0x31, 0x67, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x0a, 0x64, 0x43, 0x42, 0x44, 0x51, -+ 0x54, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x52, 0x53, -+ 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, -+ 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, -+ 0x41, 0x63, 0x4d, 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, 0x0a, 0x49, 0x45, 0x4e, 0x73, -+ 0x59, 0x58, 0x4a, 0x68, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, -+ 0x44, 0x41, 0x4a, 0x44, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, -+ 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x4d, 0x79, -+ 0x4d, 0x44, 0x45, 0x78, 0x4d, 0x6a, 0x45, 0x31, 0x4e, 0x31, 0x6f, 0x58, 0x0a, 0x44, 0x54, 0x49, -+ 0x32, 0x4d, 0x44, 0x51, 0x77, 0x4d, 0x7a, 0x45, 0x78, 0x4d, 0x6a, 0x45, 0x31, 0x4e, 0x31, 0x71, -+ 0x67, 0x4c, 0x7a, 0x41, 0x74, 0x4d, 0x41, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x64, 0x46, 0x41, 0x51, -+ 0x44, 0x41, 0x67, 0x45, 0x42, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x51, -+ 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x43, 0x4a, 0x6c, 0x44, 0x4e, 0x5a, 0x61, 0x0a, 0x6e, 0x54, -+ 0x53, 0x4a, 0x38, 0x34, 0x4f, 0x30, 0x6c, 0x56, 0x4b, 0x2f, 0x55, 0x42, 0x73, 0x35, 0x4a, 0x77, -+ 0x61, 0x73, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, -+ 0x4d, 0x43, 0x41, 0x30, 0x63, 0x41, 0x4d, 0x45, 0x51, 0x43, 0x49, 0x44, 0x44, 0x4a, 0x2f, 0x4f, -+ 0x46, 0x44, 0x6a, 0x61, 0x43, 0x70, 0x54, 0x6b, 0x2f, 0x2f, 0x33, 0x55, 0x62, 0x4a, 0x0a, 0x5a, -+ 0x51, 0x34, 0x35, 0x4f, 0x2b, 0x62, 0x6c, 0x70, 0x34, 0x59, 0x74, 0x54, 0x6b, 0x35, 0x7a, 0x55, -+ 0x6e, 0x6b, 0x79, 0x30, 0x45, 0x72, 0x7a, 0x41, 0x69, 0x42, 0x6c, 0x4f, 0x65, 0x2f, 0x6a, 0x39, -+ 0x7a, 0x54, 0x44, 0x31, 0x39, 0x38, 0x67, 0x32, 0x64, 0x2f, 0x45, 0x59, 0x77, 0x34, 0x63, 0x66, -+ 0x2f, 0x42, 0x44, 0x6d, 0x67, 0x2b, 0x4f, 0x7a, 0x68, 0x41, 0x66, 0x46, 0x62, 0x58, 0x71, 0x0a, -+ 0x2f, 0x35, 0x74, 0x50, 0x4d, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, -+ 0x44, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, -+ 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x58, 0x35, 0x30, 0x39, -+ 0x20, 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x4b, 0x59, 0x7a, -+ 0x43, 0x43, 0x43, 0x67, 0x67, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, -+ 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x63, 0x44, 0x45, 0x69, 0x4d, 0x43, -+ 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x5a, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, -+ 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x42, 0x44, 0x0a, 0x53, 0x79, 0x42, 0x51, 0x62, -+ 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, 0x53, 0x42, 0x44, 0x51, 0x54, 0x45, 0x61, 0x4d, -+ 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, -+ 0x57, 0x77, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, -+ 0x32, 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x63, 0x4d, -+ 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4a, 0x68, -+ 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x4a, 0x44, -+ 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, -+ 0x56, 0x56, 0x4d, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x0a, 0x4e, 0x44, 0x45, -+ 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x67, -+ 0x79, 0x4d, 0x7a, 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x67, 0x67, 0x6b, -+ 0x30, 0x4d, 0x44, 0x4d, 0x43, 0x46, 0x47, 0x2f, 0x44, 0x54, 0x6c, 0x41, 0x6a, 0x35, 0x79, 0x69, -+ 0x53, 0x4e, 0x44, 0x58, 0x57, 0x47, 0x71, 0x53, 0x34, 0x50, 0x47, 0x47, 0x42, 0x0a, 0x5a, 0x71, -+ 0x30, 0x31, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, -+ 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, -+ 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, 0x41, 0x4f, -+ 0x2b, 0x75, 0x62, 0x70, 0x63, 0x56, 0x2f, 0x4b, 0x45, 0x37, 0x68, 0x2b, 0x4d, 0x7a, 0x0a, 0x36, -+ 0x43, 0x59, 0x65, 0x31, 0x74, 0x6d, 0x51, 0x71, 0x53, 0x61, 0x74, 0x46, 0x77, 0x30, 0x79, 0x4e, -+ 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, -+ 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, -+ 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, 0x41, 0x50, 0x31, 0x67, 0x68, 0x6b, 0x68, 0x69, 0x0a, -+ 0x6e, 0x4c, 0x70, 0x7a, 0x42, 0x34, 0x74, 0x4e, 0x53, 0x53, 0x39, 0x4c, 0x50, 0x71, 0x64, 0x42, -+ 0x72, 0x51, 0x6a, 0x4e, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, -+ 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, -+ 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, -+ 0x0a, 0x41, 0x49, 0x72, 0x35, 0x4a, 0x42, 0x68, 0x4f, 0x48, 0x56, 0x72, 0x39, 0x33, 0x58, 0x50, -+ 0x44, 0x31, 0x6a, 0x6f, 0x53, 0x39, 0x65, 0x69, 0x31, 0x63, 0x33, 0x35, 0x57, 0x46, 0x77, 0x30, -+ 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, -+ 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, -+ 0x4b, 0x0a, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, 0x41, 0x4c, 0x45, 0x6c, 0x65, 0x58, -+ 0x6a, 0x50, 0x71, 0x63, 0x7a, 0x64, 0x42, 0x31, 0x6d, 0x72, 0x2b, 0x4d, 0x58, 0x4b, 0x63, 0x76, -+ 0x72, 0x6a, 0x70, 0x34, 0x71, 0x62, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, -+ 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, -+ 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4d, -+ 0x77, 0x49, 0x55, 0x64, 0x50, 0x36, 0x6d, 0x46, 0x4b, 0x6c, 0x79, 0x76, 0x67, 0x34, 0x6f, 0x51, -+ 0x2f, 0x49, 0x46, 0x6d, 0x44, 0x57, 0x42, 0x48, 0x74, 0x68, 0x79, 0x2b, 0x62, 0x4d, 0x58, 0x44, -+ 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, -+ 0x56, 0x6f, 0x77, 0x0a, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, -+ 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x30, 0x41, 0x68, 0x55, 0x41, 0x2b, 0x63, 0x54, 0x76, -+ 0x56, 0x72, 0x4f, 0x72, 0x53, 0x4e, 0x56, 0x33, 0x34, 0x51, 0x69, 0x36, 0x37, 0x66, 0x53, 0x2f, -+ 0x69, 0x41, 0x46, 0x43, 0x46, 0x4c, 0x6b, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, -+ 0x4e, 0x44, 0x45, 0x32, 0x0a, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, -+ 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, -+ 0x7a, 0x41, 0x68, 0x51, 0x48, 0x48, 0x65, 0x42, 0x33, 0x6a, 0x35, 0x35, 0x66, 0x78, 0x50, 0x4b, -+ 0x48, 0x6a, 0x7a, 0x44, 0x57, 0x73, 0x48, 0x79, 0x61, 0x4d, 0x4f, 0x61, 0x7a, 0x43, 0x78, 0x63, -+ 0x4e, 0x4d, 0x6a, 0x55, 0x77, 0x0a, 0x4e, 0x7a, 0x49, 0x30, 0x4d, 0x54, 0x59, 0x79, 0x4f, 0x44, -+ 0x49, 0x78, 0x57, 0x6a, 0x41, 0x4d, 0x4d, 0x41, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x64, 0x46, 0x51, -+ 0x51, 0x44, 0x43, 0x67, 0x45, 0x42, 0x4d, 0x44, 0x51, 0x43, 0x46, 0x51, 0x44, 0x4e, 0x34, 0x6b, -+ 0x4a, 0x50, 0x6c, 0x79, 0x7a, 0x71, 0x6c, 0x50, 0x38, 0x6a, 0x6d, 0x54, 0x66, 0x30, 0x32, 0x41, -+ 0x77, 0x6c, 0x41, 0x70, 0x33, 0x57, 0x0a, 0x43, 0x78, 0x63, 0x4e, 0x4d, 0x6a, 0x55, 0x77, 0x4e, -+ 0x7a, 0x49, 0x30, 0x4d, 0x54, 0x59, 0x79, 0x4f, 0x44, 0x49, 0x78, 0x57, 0x6a, 0x41, 0x4d, 0x4d, -+ 0x41, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x64, 0x46, 0x51, 0x51, 0x44, 0x43, 0x67, 0x45, 0x42, 0x4d, -+ 0x44, 0x4d, 0x43, 0x46, 0x47, 0x77, 0x7a, 0x47, 0x65, 0x55, 0x51, 0x6d, 0x32, 0x52, 0x51, 0x66, -+ 0x54, 0x7a, 0x78, 0x45, 0x79, 0x7a, 0x67, 0x0a, 0x41, 0x30, 0x6e, 0x76, 0x55, 0x6e, 0x4d, 0x5a, -+ 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, -+ 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, -+ 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, 0x41, 0x4e, 0x38, 0x49, -+ 0x31, 0x31, 0x61, 0x32, 0x61, 0x6e, 0x53, 0x58, 0x0a, 0x39, 0x44, 0x74, 0x62, 0x74, 0x59, 0x72, -+ 0x61, 0x42, 0x4e, 0x50, 0x30, 0x39, 0x36, 0x6b, 0x33, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, -+ 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, -+ 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, -+ 0x77, 0x4d, 0x77, 0x49, 0x55, 0x4b, 0x4b, 0x39, 0x49, 0x0a, 0x57, 0x32, 0x7a, 0x32, 0x66, 0x6b, -+ 0x43, 0x61, 0x4f, 0x64, 0x58, 0x4c, 0x57, 0x75, 0x35, 0x46, 0x6d, 0x50, 0x65, 0x6f, 0x2b, 0x6e, -+ 0x73, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, 0x6a, -+ 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, -+ 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x30, 0x0a, 0x41, 0x68, 0x55, 0x41, 0x2b, -+ 0x34, 0x73, 0x74, 0x72, 0x73, 0x43, 0x53, 0x79, 0x74, 0x71, 0x4b, 0x71, 0x62, 0x78, 0x50, 0x38, -+ 0x76, 0x48, 0x43, 0x44, 0x51, 0x4e, 0x47, 0x5a, 0x6f, 0x77, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, -+ 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, -+ 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, 0x0a, 0x41, 0x77, 0x6f, 0x42, -+ 0x41, 0x54, 0x41, 0x30, 0x41, 0x68, 0x55, 0x41, 0x7a, 0x55, 0x68, 0x51, 0x72, 0x46, 0x4b, 0x39, -+ 0x7a, 0x47, 0x6d, 0x6d, 0x70, 0x76, 0x42, 0x59, 0x79, 0x4c, 0x78, 0x58, 0x75, 0x39, 0x43, 0x31, -+ 0x2b, 0x47, 0x51, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, -+ 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x0a, 0x42, 0x67, 0x4e, -+ 0x56, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x30, 0x41, 0x68, 0x55, -+ 0x41, 0x6d, 0x55, 0x33, 0x54, 0x5a, 0x6d, 0x39, 0x53, 0x64, 0x66, 0x75, 0x41, 0x58, 0x35, 0x58, -+ 0x64, 0x41, 0x72, 0x31, 0x51, 0x79, 0x79, 0x5a, 0x35, 0x32, 0x4b, 0x30, 0x58, 0x44, 0x54, 0x49, -+ 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x0a, 0x4d, 0x56, -+ 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, -+ 0x6f, 0x42, 0x41, 0x54, 0x41, 0x7a, 0x41, 0x68, 0x51, 0x48, 0x41, 0x68, 0x4e, 0x70, 0x41, 0x43, -+ 0x55, 0x69, 0x64, 0x4e, 0x6b, 0x44, 0x58, 0x75, 0x33, 0x31, 0x52, 0x58, 0x52, 0x69, 0x2b, 0x74, -+ 0x44, 0x76, 0x54, 0x42, 0x63, 0x4e, 0x4d, 0x6a, 0x55, 0x77, 0x4e, 0x7a, 0x49, 0x30, 0x0a, 0x4d, -+ 0x54, 0x59, 0x79, 0x4f, 0x44, 0x49, 0x78, 0x57, 0x6a, 0x41, 0x4d, 0x4d, 0x41, 0x6f, 0x47, 0x41, -+ 0x31, 0x55, 0x64, 0x46, 0x51, 0x51, 0x44, 0x43, 0x67, 0x45, 0x42, 0x4d, 0x44, 0x4d, 0x43, 0x46, -+ 0x47, 0x48, 0x79, 0x76, 0x33, 0x50, 0x6a, 0x6d, 0x30, 0x34, 0x45, 0x71, 0x69, 0x66, 0x59, 0x41, -+ 0x62, 0x31, 0x7a, 0x30, 0x6b, 0x4d, 0x5a, 0x74, 0x62, 0x2b, 0x41, 0x46, 0x77, 0x30, 0x79, 0x0a, -+ 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, -+ 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, -+ 0x41, 0x51, 0x45, 0x77, 0x4d, 0x77, 0x49, 0x55, 0x4f, 0x5a, 0x4b, 0x2b, 0x68, 0x52, 0x75, 0x57, -+ 0x6b, 0x43, 0x37, 0x2f, 0x4f, 0x4a, 0x57, 0x65, 0x62, 0x43, 0x37, 0x2f, 0x47, 0x77, 0x5a, 0x52, -+ 0x0a, 0x70, 0x4c, 0x55, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, -+ 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, -+ 0x56, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x7a, 0x41, 0x68, 0x51, -+ 0x50, 0x32, 0x6b, 0x4f, 0x67, 0x43, 0x32, 0x6a, 0x71, 0x65, 0x62, 0x66, 0x43, 0x33, 0x71, 0x36, -+ 0x73, 0x0a, 0x43, 0x30, 0x6d, 0x4c, 0x33, 0x37, 0x4b, 0x76, 0x6b, 0x42, 0x63, 0x4e, 0x4d, 0x6a, -+ 0x55, 0x77, 0x4e, 0x7a, 0x49, 0x30, 0x4d, 0x54, 0x59, 0x79, 0x4f, 0x44, 0x49, 0x78, 0x57, 0x6a, -+ 0x41, 0x4d, 0x4d, 0x41, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x64, 0x46, 0x51, 0x51, 0x44, 0x43, 0x67, -+ 0x45, 0x42, 0x4d, 0x44, 0x4d, 0x43, 0x46, 0x47, 0x4f, 0x66, 0x45, 0x35, 0x70, 0x51, 0x51, 0x50, -+ 0x33, 0x50, 0x0a, 0x38, 0x5a, 0x48, 0x6f, 0x70, 0x50, 0x73, 0x62, 0x38, 0x49, 0x62, 0x74, 0x59, -+ 0x44, 0x6c, 0x78, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, -+ 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, -+ 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, 0x41, -+ 0x4a, 0x57, 0x64, 0x0a, 0x55, 0x7a, 0x2b, 0x53, 0x53, 0x64, 0x77, 0x65, 0x55, 0x54, 0x56, 0x45, -+ 0x7a, 0x63, 0x67, 0x77, 0x76, 0x78, 0x6d, 0x33, 0x38, 0x66, 0x4d, 0x42, 0x46, 0x77, 0x30, 0x79, -+ 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, -+ 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, -+ 0x41, 0x51, 0x45, 0x77, 0x0a, 0x4d, 0x77, 0x49, 0x55, 0x65, 0x75, 0x4e, 0x33, 0x53, 0x4b, 0x6e, -+ 0x35, 0x45, 0x76, 0x54, 0x47, 0x4f, 0x36, 0x65, 0x72, 0x42, 0x38, 0x57, 0x54, 0x7a, 0x68, 0x30, -+ 0x64, 0x45, 0x59, 0x45, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, -+ 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, -+ 0x56, 0x48, 0x52, 0x55, 0x45, 0x0a, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x7a, 0x41, 0x68, -+ 0x51, 0x54, 0x69, 0x45, 0x73, 0x7a, 0x4a, 0x70, 0x6b, 0x34, 0x77, 0x5a, 0x57, 0x71, 0x46, 0x77, -+ 0x2f, 0x4b, 0x64, 0x64, 0x6f, 0x58, 0x64, 0x54, 0x6a, 0x66, 0x43, 0x78, 0x63, 0x4e, 0x4d, 0x6a, -+ 0x55, 0x77, 0x4e, 0x7a, 0x49, 0x30, 0x4d, 0x54, 0x59, 0x79, 0x4f, 0x44, 0x49, 0x78, 0x57, 0x6a, -+ 0x41, 0x4d, 0x4d, 0x41, 0x6f, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x46, 0x51, 0x51, 0x44, 0x43, -+ 0x67, 0x45, 0x42, 0x4d, 0x44, 0x51, 0x43, 0x46, 0x51, 0x43, 0x46, 0x30, 0x38, 0x6b, 0x34, 0x47, -+ 0x33, 0x65, 0x6e, 0x34, 0x45, 0x30, 0x52, 0x6e, 0x4a, 0x35, 0x61, 0x31, 0x6e, 0x53, 0x66, 0x38, -+ 0x2f, 0x2b, 0x72, 0x68, 0x78, 0x63, 0x4e, 0x4d, 0x6a, 0x55, 0x77, 0x4e, 0x7a, 0x49, 0x30, 0x4d, -+ 0x54, 0x59, 0x79, 0x4f, 0x44, 0x49, 0x78, 0x0a, 0x57, 0x6a, 0x41, 0x4d, 0x4d, 0x41, 0x6f, 0x47, -+ 0x41, 0x31, 0x55, 0x64, 0x46, 0x51, 0x51, 0x44, 0x43, 0x67, 0x45, 0x42, 0x4d, 0x44, 0x51, 0x43, -+ 0x46, 0x51, 0x43, 0x54, 0x69, 0x48, 0x79, 0x6b, 0x51, 0x52, 0x35, 0x36, 0x6b, 0x6a, 0x76, 0x52, -+ 0x2f, 0x74, 0x4b, 0x42, 0x6d, 0x79, 0x6c, 0x4a, 0x38, 0x67, 0x47, 0x31, 0x74, 0x42, 0x63, 0x4e, -+ 0x4d, 0x6a, 0x55, 0x77, 0x4e, 0x7a, 0x49, 0x30, 0x0a, 0x4d, 0x54, 0x59, 0x79, 0x4f, 0x44, 0x49, -+ 0x78, 0x57, 0x6a, 0x41, 0x4d, 0x4d, 0x41, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x64, 0x46, 0x51, 0x51, -+ 0x44, 0x43, 0x67, 0x45, 0x42, 0x4d, 0x44, 0x4d, 0x43, 0x46, 0x43, 0x53, 0x59, 0x33, 0x47, 0x4b, -+ 0x44, 0x6b, 0x77, 0x6d, 0x57, 0x2f, 0x59, 0x76, 0x79, 0x4f, 0x6a, 0x65, 0x73, 0x76, 0x69, 0x61, -+ 0x6a, 0x76, 0x74, 0x52, 0x58, 0x46, 0x77, 0x30, 0x79, 0x0a, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, -+ 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, -+ 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, -+ 0x49, 0x56, 0x41, 0x49, 0x70, 0x6d, 0x38, 0x61, 0x64, 0x4a, 0x53, 0x49, 0x5a, 0x6e, 0x61, 0x4a, -+ 0x7a, 0x44, 0x6b, 0x44, 0x72, 0x46, 0x54, 0x47, 0x59, 0x72, 0x0a, 0x63, 0x53, 0x35, 0x7a, 0x46, -+ 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, -+ 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, -+ 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, 0x41, 0x4b, 0x2f, 0x42, 0x4e, -+ 0x68, 0x43, 0x39, 0x30, 0x32, 0x79, 0x33, 0x6d, 0x46, 0x30, 0x51, 0x0a, 0x5a, 0x49, 0x47, 0x6f, -+ 0x67, 0x4e, 0x4f, 0x67, 0x48, 0x39, 0x6f, 0x48, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, -+ 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, -+ 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, -+ 0x4e, 0x41, 0x49, 0x56, 0x41, 0x4f, 0x2f, 0x67, 0x53, 0x79, 0x77, 0x7a, 0x0a, 0x30, 0x44, 0x61, -+ 0x71, 0x79, 0x57, 0x79, 0x6d, 0x63, 0x37, 0x38, 0x65, 0x6d, 0x6b, 0x65, 0x32, 0x54, 0x56, 0x79, -+ 0x37, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, -+ 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, -+ 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, 0x0a, 0x41, 0x49, -+ 0x50, 0x5a, 0x72, 0x49, 0x32, 0x4c, 0x74, 0x51, 0x6e, 0x52, 0x78, 0x73, 0x67, 0x4a, 0x72, 0x58, -+ 0x45, 0x75, 0x68, 0x44, 0x42, 0x56, 0x6e, 0x74, 0x66, 0x7a, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, -+ 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, -+ 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x0a, 0x41, -+ 0x51, 0x45, 0x77, 0x4d, 0x77, 0x49, 0x55, 0x65, 0x54, 0x48, 0x39, 0x55, 0x4c, 0x55, 0x48, 0x48, -+ 0x42, 0x75, 0x2f, 0x78, 0x62, 0x65, 0x32, 0x33, 0x74, 0x69, 0x30, 0x57, 0x35, 0x32, 0x4c, 0x68, -+ 0x53, 0x6b, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, -+ 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x0a, -+ 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x7a, 0x41, 0x68, 0x51, 0x66, -+ 0x6f, 0x67, 0x34, 0x70, 0x63, 0x4c, 0x33, 0x6c, 0x31, 0x58, 0x39, 0x37, 0x6a, 0x64, 0x2b, 0x44, -+ 0x4f, 0x55, 0x68, 0x4f, 0x48, 0x78, 0x30, 0x49, 0x49, 0x78, 0x63, 0x4e, 0x4d, 0x6a, 0x55, 0x77, -+ 0x4e, 0x7a, 0x49, 0x30, 0x4d, 0x54, 0x59, 0x79, 0x4f, 0x44, 0x49, 0x78, 0x57, 0x6a, 0x41, 0x4d, -+ 0x0a, 0x4d, 0x41, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x64, 0x46, 0x51, 0x51, 0x44, 0x43, 0x67, 0x45, -+ 0x42, 0x4d, 0x44, 0x4d, 0x43, 0x46, 0x42, 0x36, 0x48, 0x73, 0x73, 0x4f, 0x7a, 0x4c, 0x59, 0x30, -+ 0x6a, 0x35, 0x42, 0x48, 0x4f, 0x38, 0x30, 0x47, 0x58, 0x75, 0x56, 0x72, 0x77, 0x79, 0x4b, 0x33, -+ 0x31, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, -+ 0x34, 0x0a, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, -+ 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x4e, 0x41, 0x49, 0x56, 0x41, 0x4a, -+ 0x72, 0x39, 0x4c, 0x75, 0x6b, 0x4b, 0x52, 0x7a, 0x56, 0x51, 0x6f, 0x57, 0x66, 0x5a, 0x6c, 0x70, -+ 0x45, 0x55, 0x4e, 0x38, 0x64, 0x51, 0x4c, 0x52, 0x38, 0x4a, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, -+ 0x41, 0x33, 0x0a, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, -+ 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x41, -+ 0x51, 0x45, 0x77, 0x4d, 0x77, 0x49, 0x55, 0x52, 0x49, 0x47, 0x77, 0x38, 0x52, 0x63, 0x6f, 0x6f, -+ 0x54, 0x74, 0x70, 0x62, 0x54, 0x36, 0x70, 0x78, 0x33, 0x43, 0x67, 0x73, 0x56, 0x37, 0x46, 0x6a, -+ 0x64, 0x6f, 0x58, 0x0a, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, -+ 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, -+ 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x30, 0x41, 0x68, 0x55, 0x41, -+ 0x70, 0x34, 0x57, 0x66, 0x56, 0x35, 0x67, 0x75, 0x38, 0x4f, 0x5a, 0x39, 0x4e, 0x37, 0x79, 0x4f, -+ 0x38, 0x75, 0x39, 0x61, 0x0a, 0x79, 0x44, 0x58, 0x2f, 0x47, 0x71, 0x6b, 0x58, 0x44, 0x54, 0x49, -+ 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, -+ 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, -+ 0x42, 0x41, 0x54, 0x41, 0x30, 0x41, 0x68, 0x55, 0x41, 0x6e, 0x57, 0x64, 0x31, 0x4f, 0x34, 0x48, -+ 0x6b, 0x63, 0x4a, 0x43, 0x75, 0x0a, 0x70, 0x32, 0x50, 0x37, 0x37, 0x45, 0x78, 0x46, 0x53, 0x62, -+ 0x7a, 0x62, 0x6d, 0x54, 0x4d, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, -+ 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, -+ 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x7a, 0x41, 0x68, -+ 0x51, 0x30, 0x76, 0x37, 0x74, 0x36, 0x0a, 0x48, 0x5a, 0x78, 0x57, 0x67, 0x55, 0x66, 0x68, 0x47, -+ 0x4c, 0x59, 0x55, 0x39, 0x37, 0x64, 0x75, 0x30, 0x2b, 0x39, 0x6f, 0x33, 0x78, 0x63, 0x4e, 0x4d, -+ 0x6a, 0x55, 0x77, 0x4e, 0x7a, 0x49, 0x30, 0x4d, 0x54, 0x59, 0x79, 0x4f, 0x44, 0x49, 0x78, 0x57, -+ 0x6a, 0x41, 0x4d, 0x4d, 0x41, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x64, 0x46, 0x51, 0x51, 0x44, 0x43, -+ 0x67, 0x45, 0x42, 0x4d, 0x44, 0x4d, 0x43, 0x0a, 0x46, 0x43, 0x77, 0x38, 0x78, 0x76, 0x36, 0x53, -+ 0x65, 0x64, 0x73, 0x56, 0x46, 0x74, 0x58, 0x4f, 0x4f, 0x66, 0x4b, 0x6f, 0x6d, 0x4d, 0x32, 0x6c, -+ 0x6f, 0x58, 0x58, 0x68, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x54, 0x41, 0x33, 0x4d, 0x6a, 0x51, 0x78, -+ 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x6a, 0x46, 0x61, 0x4d, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, -+ 0x56, 0x52, 0x30, 0x56, 0x42, 0x41, 0x4d, 0x4b, 0x0a, 0x41, 0x51, 0x45, 0x77, 0x4d, 0x77, 0x49, -+ 0x55, 0x63, 0x58, 0x6c, 0x49, 0x61, 0x48, 0x55, 0x4a, 0x49, 0x30, 0x76, 0x70, 0x65, 0x65, 0x53, -+ 0x33, 0x33, 0x4f, 0x62, 0x7a, 0x47, 0x2b, 0x39, 0x6b, 0x74, 0x6f, 0x77, 0x58, 0x44, 0x54, 0x49, -+ 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, -+ 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, -+ 0x6f, 0x42, 0x41, 0x54, 0x41, 0x30, 0x41, 0x68, 0x55, 0x41, 0x6e, 0x58, 0x62, 0x76, 0x4c, 0x44, -+ 0x6e, 0x42, 0x4e, 0x75, 0x68, 0x6c, 0x69, 0x32, 0x35, 0x7a, 0x6c, 0x72, 0x48, 0x58, 0x52, 0x46, -+ 0x6f, 0x6e, 0x59, 0x78, 0x38, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, -+ 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x0a, 0x44, 0x44, 0x41, 0x4b, 0x42, -+ 0x67, 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x30, 0x41, -+ 0x68, 0x55, 0x41, 0x77, 0x2b, 0x41, 0x6c, 0x2f, 0x4b, 0x6d, 0x56, 0x38, 0x32, 0x39, 0x5a, 0x74, -+ 0x49, 0x52, 0x6e, 0x6b, 0x35, 0x34, 0x2b, 0x4e, 0x4f, 0x59, 0x32, 0x47, 0x6d, 0x38, 0x58, 0x44, -+ 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x0a, 0x4d, 0x6a, 0x67, 0x79, -+ 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, -+ 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, 0x30, 0x41, 0x68, 0x55, 0x41, 0x6a, 0x46, 0x39, 0x72, -+ 0x4d, 0x6c, 0x66, 0x61, 0x42, 0x62, 0x46, 0x30, 0x4b, 0x65, 0x4c, 0x6d, 0x47, 0x36, 0x6c, 0x6c, -+ 0x31, 0x6e, 0x4d, 0x77, 0x59, 0x47, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x31, 0x0a, 0x4d, 0x44, 0x63, -+ 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, 0x6a, 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, -+ 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x54, 0x41, -+ 0x30, 0x41, 0x68, 0x55, 0x41, 0x6f, 0x58, 0x78, 0x52, 0x63, 0x69, 0x37, 0x42, 0x34, 0x4d, 0x4d, -+ 0x6e, 0x6a, 0x2b, 0x69, 0x39, 0x38, 0x46, 0x49, 0x46, 0x6e, 0x4c, 0x37, 0x45, 0x0a, 0x35, 0x6b, -+ 0x67, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x45, 0x32, 0x4d, 0x6a, -+ 0x67, 0x79, 0x4d, 0x56, 0x6f, 0x77, 0x44, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, -+ 0x55, 0x45, 0x41, 0x77, 0x6f, 0x42, 0x41, 0x61, 0x41, 0x76, 0x4d, 0x43, 0x30, 0x77, 0x43, 0x67, -+ 0x59, 0x44, 0x56, 0x52, 0x30, 0x55, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x45, 0x77, 0x0a, 0x48, -+ 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x6c, -+ 0x57, 0x39, 0x64, 0x7a, 0x62, 0x30, 0x62, 0x34, 0x65, 0x6c, 0x41, 0x53, 0x63, 0x6e, 0x55, 0x39, -+ 0x44, 0x50, 0x4f, 0x41, 0x56, 0x63, 0x4c, 0x33, 0x6c, 0x51, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, -+ 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x51, 0x41, 0x77, 0x0a, -+ 0x52, 0x67, 0x49, 0x68, 0x41, 0x4d, 0x64, 0x76, 0x4c, 0x47, 0x6a, 0x57, 0x53, 0x4f, 0x69, 0x4e, -+ 0x32, 0x4f, 0x36, 0x37, 0x73, 0x4f, 0x36, 0x59, 0x62, 0x33, 0x32, 0x2f, 0x5a, 0x51, 0x33, 0x55, -+ 0x6f, 0x66, 0x47, 0x2b, 0x6a, 0x53, 0x6e, 0x59, 0x7a, 0x72, 0x67, 0x2f, 0x4c, 0x4b, 0x61, 0x32, -+ 0x41, 0x69, 0x45, 0x41, 0x6d, 0x74, 0x74, 0x2b, 0x4b, 0x49, 0x57, 0x59, 0x42, 0x4b, 0x78, 0x68, -+ 0x0a, 0x6e, 0x42, 0x61, 0x43, 0x41, 0x49, 0x75, 0x47, 0x30, 0x35, 0x4c, 0x68, 0x6e, 0x7a, 0x6f, -+ 0x38, 0x76, 0x43, 0x65, 0x39, 0x34, 0x69, 0x71, 0x39, 0x4e, 0x55, 0x4f, 0x66, 0x79, 0x6f, 0x38, -+ 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, -+ 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, -+ 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, -+ 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6a, 0x54, 0x43, 0x43, 0x41, 0x6a, -+ 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x66, 0x6a, 0x69, 0x43, 0x31, 0x66, -+ 0x74, 0x56, 0x4b, 0x55, 0x70, 0x41, 0x53, 0x59, 0x35, 0x46, 0x68, 0x41, 0x50, 0x70, 0x46, 0x4a, -+ 0x47, 0x39, 0x39, 0x46, 0x55, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, -+ 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, -+ 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, -+ 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, -+ 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, -+ 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, -+ 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, -+ 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, -+ 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, -+ 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, -+ 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x55, -+ 0x77, 0x4e, 0x6a, 0x41, 0x35, 0x4d, 0x6a, 0x55, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, -+ 0x79, 0x4d, 0x44, 0x55, 0x77, 0x4e, 0x6a, 0x41, 0x35, 0x4d, 0x6a, 0x55, 0x77, 0x4d, 0x46, 0x6f, -+ 0x77, 0x62, 0x44, 0x45, 0x65, 0x4d, 0x42, 0x77, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, -+ 0x77, 0x56, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, -+ 0x52, 0x44, 0x51, 0x69, 0x42, 0x54, 0x61, 0x57, 0x64, 0x75, 0x61, 0x57, 0x35, 0x6e, 0x4d, 0x52, -+ 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, -+ 0x52, 0x6c, 0x62, 0x43, 0x42, 0x44, 0x62, 0x33, 0x4a, 0x77, 0x0a, 0x62, 0x33, 0x4a, 0x68, 0x64, -+ 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, -+ 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, -+ 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, -+ 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, -+ 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x42, 0x5a, 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, 0x47, -+ 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, -+ 0x41, 0x77, 0x45, 0x48, 0x41, 0x30, 0x49, 0x41, 0x42, 0x45, 0x4e, 0x46, 0x47, 0x38, 0x78, 0x7a, -+ 0x79, 0x64, 0x57, 0x52, 0x66, 0x4b, 0x39, 0x32, 0x62, 0x6d, 0x47, 0x76, 0x0a, 0x50, 0x2b, 0x6d, -+ 0x41, 0x68, 0x39, 0x31, 0x50, 0x45, 0x79, 0x56, 0x37, 0x4a, 0x68, 0x36, 0x46, 0x47, 0x4a, 0x64, -+ 0x35, 0x6e, 0x64, 0x45, 0x39, 0x61, 0x42, 0x48, 0x37, 0x52, 0x33, 0x45, 0x34, 0x41, 0x37, 0x75, -+ 0x62, 0x72, 0x6c, 0x68, 0x2f, 0x7a, 0x4e, 0x33, 0x43, 0x34, 0x78, 0x76, 0x70, 0x6f, 0x6f, 0x75, -+ 0x47, 0x6c, 0x69, 0x72, 0x4d, 0x62, 0x61, 0x2b, 0x57, 0x32, 0x6c, 0x6a, 0x75, 0x0a, 0x79, 0x70, -+ 0x61, 0x6a, 0x67, 0x62, 0x55, 0x77, 0x67, 0x62, 0x49, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, -+ 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, -+ 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, -+ 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x55, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x0a, 0x42, -+ 0x45, 0x73, 0x77, 0x53, 0x54, 0x42, 0x48, 0x6f, 0x45, 0x57, 0x67, 0x51, 0x34, 0x5a, 0x42, 0x61, -+ 0x48, 0x52, 0x30, 0x63, 0x48, 0x4d, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, -+ 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x58, 0x4d, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, -+ 0x33, 0x52, 0x6c, 0x5a, 0x48, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x0a, -+ 0x4c, 0x6d, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x39, 0x4a, -+ 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x46, 0x4e, 0x48, 0x57, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, -+ 0x51, 0x53, 0x35, 0x6b, 0x5a, 0x58, 0x49, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, -+ 0x42, 0x42, 0x59, 0x45, 0x46, 0x48, 0x34, 0x34, 0x67, 0x74, 0x58, 0x37, 0x56, 0x53, 0x6c, 0x4b, -+ 0x0a, 0x51, 0x45, 0x6d, 0x4f, 0x52, 0x59, 0x51, 0x44, 0x36, 0x52, 0x53, 0x52, 0x76, 0x66, 0x52, -+ 0x56, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, -+ 0x45, 0x41, 0x77, 0x49, 0x47, 0x77, 0x44, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, -+ 0x42, 0x41, 0x66, 0x38, 0x45, 0x41, 0x6a, 0x41, 0x41, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, -+ 0x47, 0x0a, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x30, 0x6b, 0x41, 0x4d, 0x45, -+ 0x59, 0x43, 0x49, 0x51, 0x44, 0x64, 0x6d, 0x6d, 0x52, 0x75, 0x41, 0x6f, 0x33, 0x71, 0x43, 0x4f, -+ 0x38, 0x54, 0x43, 0x31, 0x49, 0x6f, 0x4a, 0x4d, 0x49, 0x54, 0x41, 0x6f, 0x4f, 0x45, 0x77, 0x34, -+ 0x64, 0x6c, 0x67, 0x45, 0x42, 0x48, 0x7a, 0x53, 0x7a, 0x31, 0x54, 0x75, 0x4d, 0x53, 0x54, 0x41, -+ 0x49, 0x68, 0x0a, 0x41, 0x4b, 0x56, 0x54, 0x71, 0x4f, 0x6b, 0x74, 0x35, 0x39, 0x2b, 0x63, 0x6f, -+ 0x30, 0x4f, 0x33, 0x6d, 0x33, 0x68, 0x43, 0x2b, 0x76, 0x35, 0x46, 0x62, 0x30, 0x30, 0x46, 0x6a, -+ 0x59, 0x57, 0x63, 0x67, 0x65, 0x75, 0x33, 0x45, 0x69, 0x6a, 0x4f, 0x55, 0x4c, 0x6f, 0x35, 0x0a, -+ 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, -+ 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, -+ 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, -+ 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6a, 0x7a, 0x43, 0x43, 0x41, 0x6a, -+ 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, -+ 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, -+ 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, -+ 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, -+ 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, -+ 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, -+ 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, -+ 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, -+ 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, -+ 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, -+ 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, -+ 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, -+ 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4d, 0x44, 0x55, -+ 0x79, 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x55, 0x78, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x51, -+ 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, -+ 0x77, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, -+ 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, -+ 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, -+ 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, -+ 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x0a, 0x61, 0x57, 0x39, 0x75, 0x4d, -+ 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, -+ 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, -+ 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, -+ 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x56, 0x54, -+ 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, -+ 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, -+ 0x51, 0x67, 0x41, 0x45, 0x43, 0x36, 0x6e, 0x45, 0x77, 0x4d, 0x44, 0x49, 0x59, 0x5a, 0x4f, 0x6a, -+ 0x2f, 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, 0x4b, 0x69, 0x37, 0x0a, 0x31, 0x4f, 0x69, -+ 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, 0x4a, 0x66, 0x56, -+ 0x6e, 0x6b, 0x59, 0x34, 0x75, 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, 0x59, 0x4c, 0x30, 0x4d, 0x78, -+ 0x4f, 0x34, 0x6d, 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, -+ 0x46, 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, 0x7a, -+ 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, -+ 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, -+ 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, -+ 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x0a, 0x4d, -+ 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, -+ 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, -+ 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x63, -+ 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x0a, -+ 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, -+ 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, -+ 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, -+ 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, -+ 0x0a, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, -+ 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, -+ 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, -+ 0x49, 0x4d, 0x41, 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, 0x67, 0x59, -+ 0x49, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x51, -+ 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, 0x52, 0x2b, 0x53, -+ 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4e, 0x6f, 0x6f, 0x77, 0x4c, 0x75, 0x50, 0x52, 0x4c, 0x73, -+ 0x57, 0x47, 0x66, 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, -+ 0x77, 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, 0x73, -+ 0x2b, 0x58, 0x6f, 0x35, 0x6f, 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, 0x78, 0x48, 0x52, -+ 0x41, 0x76, 0x5a, 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, 0x63, 0x76, 0x71, 0x52, 0x58, 0x61, -+ 0x71, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, -+ 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, 0x7b, -+ 0x22, 0x74, 0x63, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x69, 0x64, 0x22, 0x3a, -+ 0x22, 0x54, 0x44, 0x58, 0x22, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, -+ 0x33, 0x2c, 0x22, 0x69, 0x73, 0x73, 0x75, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x32, -+ 0x30, 0x32, 0x34, 0x2d, 0x30, 0x37, 0x2d, 0x31, 0x35, 0x54, 0x31, 0x34, 0x3a, 0x33, 0x31, 0x3a, -+ 0x31, 0x32, 0x5a, 0x22, 0x2c, 0x22, 0x6e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, -+ 0x22, 0x3a, 0x22, 0x32, 0x30, 0x32, 0x34, 0x2d, 0x30, 0x38, 0x2d, 0x31, 0x34, 0x54, 0x31, 0x34, -+ 0x3a, 0x33, 0x31, 0x3a, 0x31, 0x32, 0x5a, 0x22, 0x2c, 0x22, 0x66, 0x6d, 0x73, 0x70, 0x63, 0x22, -+ 0x3a, 0x22, 0x39, 0x30, 0x63, 0x30, 0x36, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, -+ 0x22, 0x70, 0x63, 0x65, 0x49, 0x64, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x22, -+ 0x74, 0x63, 0x62, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x74, 0x63, 0x62, 0x45, -+ 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4e, 0x75, 0x6d, -+ 0x62, 0x65, 0x72, 0x22, 0x3a, 0x31, 0x36, 0x2c, 0x22, 0x74, 0x64, 0x78, 0x4d, 0x6f, 0x64, 0x75, -+ 0x6c, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x6d, 0x72, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0x3a, -+ 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x22, 0x2c, 0x22, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x3a, -+ 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x22, 0x2c, 0x22, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x4d, 0x61, -+ 0x73, 0x6b, 0x22, 0x3a, 0x22, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x22, 0x7d, 0x2c, 0x22, 0x74, 0x64, 0x78, 0x4d, 0x6f, 0x64, 0x75, -+ 0x6c, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x7b, -+ 0x22, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x54, 0x44, 0x58, 0x5f, 0x30, 0x33, 0x22, 0x2c, 0x22, 0x6d, -+ 0x72, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x61, 0x74, 0x74, -+ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x61, 0x74, 0x74, -+ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x22, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x22, 0x2c, -+ 0x22, 0x74, 0x63, 0x62, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x74, -+ 0x63, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x69, 0x73, 0x76, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x7d, -+ 0x2c, 0x22, 0x74, 0x63, 0x62, 0x44, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x32, 0x33, -+ 0x2d, 0x30, 0x38, 0x2d, 0x30, 0x39, 0x54, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x5a, -+ 0x22, 0x2c, 0x22, 0x74, 0x63, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x55, -+ 0x70, 0x54, 0x6f, 0x44, 0x61, 0x74, 0x65, 0x22, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x69, 0x64, -+ 0x22, 0x3a, 0x22, 0x54, 0x44, 0x58, 0x5f, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x6d, 0x72, 0x73, 0x69, -+ 0x67, 0x6e, 0x65, 0x72, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, -+ 0x75, 0x74, 0x65, 0x73, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, -+ 0x75, 0x74, 0x65, 0x73, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x22, 0x46, 0x46, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x22, 0x2c, 0x22, 0x74, 0x63, -+ 0x62, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x74, 0x63, 0x62, 0x22, -+ 0x3a, 0x7b, 0x22, 0x69, 0x73, 0x76, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x7d, 0x2c, 0x22, 0x74, -+ 0x63, 0x62, 0x44, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x32, 0x33, 0x2d, 0x30, 0x38, -+ 0x2d, 0x30, 0x39, 0x54, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x5a, 0x22, 0x2c, 0x22, -+ 0x74, 0x63, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x55, 0x70, 0x54, 0x6f, -+ 0x44, 0x61, 0x74, 0x65, 0x22, 0x7d, 0x5d, 0x7d, 0x5d, 0x2c, 0x22, 0x74, 0x63, 0x62, 0x4c, 0x65, -+ 0x76, 0x65, 0x6c, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x74, 0x63, 0x62, 0x22, 0x3a, 0x7b, 0x22, -+ 0x73, 0x67, 0x78, 0x74, 0x63, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, -+ 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, 0x74, -+ 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x42, 0x49, 0x4f, 0x53, 0x22, 0x2c, 0x22, 0x74, -+ 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x45, 0x61, 0x72, 0x6c, 0x79, 0x20, 0x4d, 0x69, 0x63, 0x72, -+ 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x7d, 0x2c, 0x7b, -+ 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, -+ 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, -+ 0x65, 0x22, 0x3a, 0x22, 0x53, 0x47, 0x58, 0x20, 0x4c, 0x61, 0x74, 0x65, 0x20, 0x4d, 0x69, 0x63, -+ 0x72, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x7d, 0x2c, -+ 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, -+ 0x72, 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, 0x22, 0x74, 0x79, -+ 0x70, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x58, 0x54, 0x20, 0x53, 0x49, 0x4e, 0x49, 0x54, 0x22, 0x7d, -+ 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, -+ 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x42, 0x49, 0x4f, 0x53, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, -+ 0x76, 0x6e, 0x22, 0x3a, 0x33, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, -+ 0x3a, 0x22, 0x42, 0x49, 0x4f, 0x53, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, -+ 0x31, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x42, 0x49, -+ 0x4f, 0x53, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, -+ 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x33, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, -+ 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, -+ 0x65, 0x22, 0x3a, 0x22, 0x53, 0x45, 0x41, 0x4d, 0x4c, 0x44, 0x52, 0x20, 0x41, 0x43, 0x4d, 0x22, -+ 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, -+ 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, -+ 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, -+ 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, -+ 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, -+ 0x7d, 0x5d, 0x2c, 0x22, 0x70, 0x63, 0x65, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x31, 0x33, 0x2c, 0x22, -+ 0x74, 0x64, 0x78, 0x74, 0x63, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, -+ 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x34, 0x2c, 0x22, 0x63, 0x61, 0x74, -+ 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, -+ 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x44, 0x58, 0x20, 0x4d, 0x6f, 0x64, 0x75, -+ 0x6c, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x63, -+ 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, -+ 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x44, 0x58, 0x20, 0x4d, 0x6f, -+ 0x64, 0x75, 0x6c, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, -+ 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, -+ 0x4d, 0x4d, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x44, 0x58, 0x20, -+ 0x4c, 0x61, 0x74, 0x65, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x55, -+ 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, -+ 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, -+ 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, -+ 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, -+ 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, -+ 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, -+ 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, -+ 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, -+ 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x5d, 0x7d, 0x2c, 0x22, 0x74, 0x63, 0x62, -+ 0x44, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x32, 0x33, 0x2d, 0x30, 0x38, 0x2d, 0x30, -+ 0x39, 0x54, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x5a, 0x22, 0x2c, 0x22, 0x74, 0x63, -+ 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x55, 0x70, 0x54, 0x6f, 0x44, 0x61, -+ 0x74, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x63, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x73, 0x67, -+ 0x78, 0x74, 0x63, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a, -+ 0x5b, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, -+ 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x42, 0x49, 0x4f, 0x53, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, -+ 0x65, 0x22, 0x3a, 0x22, 0x45, 0x61, 0x72, 0x6c, 0x79, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x63, -+ 0x6f, 0x64, 0x65, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, -+ 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, -+ 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, -+ 0x3a, 0x22, 0x53, 0x47, 0x58, 0x20, 0x4c, 0x61, 0x74, 0x65, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f, -+ 0x63, 0x6f, 0x64, 0x65, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, -+ 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, -+ 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, -+ 0x22, 0x3a, 0x22, 0x54, 0x58, 0x54, 0x20, 0x53, 0x49, 0x4e, 0x49, 0x54, 0x22, 0x7d, 0x2c, 0x7b, -+ 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, -+ 0x79, 0x22, 0x3a, 0x22, 0x42, 0x49, 0x4f, 0x53, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, -+ 0x22, 0x3a, 0x33, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, -+ 0x42, 0x49, 0x4f, 0x53, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x31, 0x2c, -+ 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x42, 0x49, 0x4f, 0x53, -+ 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, -+ 0x76, 0x6e, 0x22, 0x3a, 0x33, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, -+ 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, -+ 0x3a, 0x22, 0x53, 0x45, 0x41, 0x4d, 0x4c, 0x44, 0x52, 0x20, 0x41, 0x43, 0x4d, 0x22, 0x7d, 0x2c, -+ 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, -+ 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, -+ 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, -+ 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, -+ 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x5d, -+ 0x2c, 0x22, 0x70, 0x63, 0x65, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x35, 0x2c, 0x22, 0x74, 0x64, 0x78, -+ 0x74, 0x63, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a, 0x5b, -+ 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x34, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, -+ 0x72, 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, 0x22, 0x74, 0x79, -+ 0x70, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x44, 0x58, 0x20, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, -+ 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, -+ 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, 0x2c, 0x22, -+ 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x44, 0x58, 0x20, 0x4d, 0x6f, 0x64, 0x75, 0x6c, -+ 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x61, -+ 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x4f, 0x53, 0x2f, 0x56, 0x4d, 0x4d, 0x22, -+ 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x44, 0x58, 0x20, 0x4c, 0x61, 0x74, -+ 0x65, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x55, 0x70, 0x64, 0x61, -+ 0x74, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, -+ 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, -+ 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, -+ 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, -+ 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, -+ 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, -+ 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, -+ 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x73, -+ 0x76, 0x6e, 0x22, 0x3a, 0x30, 0x7d, 0x5d, 0x7d, 0x2c, 0x22, 0x74, 0x63, 0x62, 0x44, 0x61, 0x74, -+ 0x65, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x30, 0x31, 0x2d, 0x30, 0x34, 0x54, 0x30, -+ 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x5a, 0x22, 0x2c, 0x22, 0x74, 0x63, 0x62, 0x53, 0x74, -+ 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x4f, 0x75, 0x74, 0x4f, 0x66, 0x44, 0x61, 0x74, 0x65, -+ 0x22, 0x2c, 0x22, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x49, 0x44, 0x73, 0x22, 0x3a, -+ 0x5b, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, 0x31, 0x30, 0x36, -+ 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, 0x31, 0x31, -+ 0x35, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, 0x31, -+ 0x33, 0x35, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, -+ 0x32, 0x30, 0x33, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, -+ 0x30, 0x32, 0x32, 0x30, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, -+ 0x30, 0x30, 0x32, 0x33, 0x33, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, -+ 0x2d, 0x30, 0x30, 0x32, 0x37, 0x30, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, -+ 0x41, 0x2d, 0x30, 0x30, 0x32, 0x39, 0x33, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, 0x2d, -+ 0x53, 0x41, 0x2d, 0x30, 0x30, 0x33, 0x32, 0x30, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x4c, -+ 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, 0x33, 0x32, 0x39, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, 0x45, -+ 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, 0x33, 0x38, 0x31, 0x22, 0x2c, 0x22, 0x49, 0x4e, 0x54, -+ 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, 0x33, 0x38, 0x39, 0x22, 0x2c, 0x22, 0x49, 0x4e, -+ 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, 0x34, 0x37, 0x37, 0x22, 0x2c, 0x22, 0x49, -+ 0x4e, 0x54, 0x45, 0x4c, 0x2d, 0x53, 0x41, 0x2d, 0x30, 0x30, 0x38, 0x33, 0x37, 0x22, 0x5d, 0x7d, -+ 0x5d, 0x7d, 0x2c, 0x22, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3a, 0x22, -+ 0x65, 0x38, 0x65, 0x31, 0x35, 0x63, 0x31, 0x37, 0x65, 0x34, 0x32, 0x63, 0x38, 0x34, 0x33, 0x38, -+ 0x34, 0x65, 0x33, 0x37, 0x33, 0x31, 0x64, 0x32, 0x64, 0x36, 0x64, 0x32, 0x63, 0x64, 0x66, 0x30, -+ 0x31, 0x63, 0x64, 0x39, 0x34, 0x62, 0x34, 0x65, 0x31, 0x65, 0x34, 0x36, 0x66, 0x64, 0x37, 0x32, -+ 0x33, 0x32, 0x38, 0x64, 0x31, 0x66, 0x35, 0x32, 0x32, 0x36, 0x36, 0x31, 0x63, 0x30, 0x36, 0x66, -+ 0x37, 0x65, 0x65, 0x36, 0x39, 0x65, 0x37, 0x63, 0x35, 0x65, 0x38, 0x66, 0x34, 0x37, 0x38, 0x62, -+ 0x64, 0x34, 0x61, 0x36, 0x38, 0x61, 0x32, 0x33, 0x30, 0x64, 0x35, 0x34, 0x31, 0x32, 0x30, 0x63, -+ 0x30, 0x38, 0x66, 0x63, 0x66, 0x62, 0x61, 0x65, 0x39, 0x30, 0x36, 0x38, 0x34, 0x61, 0x33, 0x37, -+ 0x32, 0x32, 0x33, 0x64, 0x38, 0x35, 0x38, 0x30, 0x62, 0x61, 0x61, 0x30, 0x64, 0x65, 0x64, 0x35, -+ 0x22, 0x7d, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, -+ 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, -+ 0x49, 0x49, 0x43, 0x6a, 0x54, 0x43, 0x43, 0x41, 0x6a, 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, -+ 0x67, 0x49, 0x55, 0x66, 0x6a, 0x69, 0x43, 0x31, 0x66, 0x74, 0x56, 0x4b, 0x55, 0x70, 0x41, 0x53, -+ 0x59, 0x35, 0x46, 0x68, 0x41, 0x50, 0x70, 0x46, 0x4a, 0x47, 0x39, 0x39, 0x46, 0x55, 0x77, 0x43, -+ 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, -+ 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, -+ 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, -+ 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, -+ 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, -+ 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, -+ 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, -+ 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, -+ 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, -+ 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, -+ 0x34, 0x58, 0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x55, 0x77, 0x4e, 0x6a, 0x41, 0x35, 0x4d, 0x6a, -+ 0x55, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x79, 0x4d, 0x44, 0x55, 0x77, 0x4e, 0x6a, -+ 0x41, 0x35, 0x4d, 0x6a, 0x55, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x62, 0x44, 0x45, 0x65, 0x4d, 0x42, -+ 0x77, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x56, 0x53, 0x57, 0x35, 0x30, 0x5a, -+ 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x52, 0x44, 0x51, 0x69, 0x42, 0x54, 0x61, -+ 0x57, 0x64, 0x75, 0x61, 0x57, 0x35, 0x6e, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, 0x56, -+ 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x43, 0x42, 0x44, 0x62, -+ 0x33, 0x4a, 0x77, 0x0a, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, -+ 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, -+ 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, -+ 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, -+ 0x43, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x42, -+ 0x5a, 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, -+ 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, 0x41, 0x30, 0x49, -+ 0x41, 0x42, 0x45, 0x4e, 0x46, 0x47, 0x38, 0x78, 0x7a, 0x79, 0x64, 0x57, 0x52, 0x66, 0x4b, 0x39, -+ 0x32, 0x62, 0x6d, 0x47, 0x76, 0x0a, 0x50, 0x2b, 0x6d, 0x41, 0x68, 0x39, 0x31, 0x50, 0x45, 0x79, -+ 0x56, 0x37, 0x4a, 0x68, 0x36, 0x46, 0x47, 0x4a, 0x64, 0x35, 0x6e, 0x64, 0x45, 0x39, 0x61, 0x42, -+ 0x48, 0x37, 0x52, 0x33, 0x45, 0x34, 0x41, 0x37, 0x75, 0x62, 0x72, 0x6c, 0x68, 0x2f, 0x7a, 0x4e, -+ 0x33, 0x43, 0x34, 0x78, 0x76, 0x70, 0x6f, 0x6f, 0x75, 0x47, 0x6c, 0x69, 0x72, 0x4d, 0x62, 0x61, -+ 0x2b, 0x57, 0x32, 0x6c, 0x6a, 0x75, 0x0a, 0x79, 0x70, 0x61, 0x6a, 0x67, 0x62, 0x55, 0x77, 0x67, -+ 0x62, 0x49, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, -+ 0x6f, 0x41, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, -+ 0x37, 0x53, 0x56, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x55, -+ 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x0a, 0x42, 0x45, 0x73, 0x77, 0x53, 0x54, 0x42, 0x48, -+ 0x6f, 0x45, 0x57, 0x67, 0x51, 0x34, 0x5a, 0x42, 0x61, 0x48, 0x52, 0x30, 0x63, 0x48, 0x4d, 0x36, -+ 0x4c, 0x79, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, -+ 0x5a, 0x58, 0x4d, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x48, 0x4e, 0x6c, -+ 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x0a, 0x4c, 0x6d, 0x6c, 0x75, 0x64, 0x47, 0x56, -+ 0x73, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x39, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x46, 0x4e, -+ 0x48, 0x57, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, 0x51, 0x53, 0x35, 0x6b, 0x5a, 0x58, 0x49, -+ 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x48, 0x34, -+ 0x34, 0x67, 0x74, 0x58, 0x37, 0x56, 0x53, 0x6c, 0x4b, 0x0a, 0x51, 0x45, 0x6d, 0x4f, 0x52, 0x59, -+ 0x51, 0x44, 0x36, 0x52, 0x53, 0x52, 0x76, 0x66, 0x52, 0x56, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, -+ 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x47, 0x77, 0x44, -+ 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x41, 0x6a, -+ 0x41, 0x41, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, 0x47, 0x0a, 0x53, 0x4d, 0x34, 0x39, 0x42, -+ 0x41, 0x4d, 0x43, 0x41, 0x30, 0x6b, 0x41, 0x4d, 0x45, 0x59, 0x43, 0x49, 0x51, 0x44, 0x64, 0x6d, -+ 0x6d, 0x52, 0x75, 0x41, 0x6f, 0x33, 0x71, 0x43, 0x4f, 0x38, 0x54, 0x43, 0x31, 0x49, 0x6f, 0x4a, -+ 0x4d, 0x49, 0x54, 0x41, 0x6f, 0x4f, 0x45, 0x77, 0x34, 0x64, 0x6c, 0x67, 0x45, 0x42, 0x48, 0x7a, -+ 0x53, 0x7a, 0x31, 0x54, 0x75, 0x4d, 0x53, 0x54, 0x41, 0x49, 0x68, 0x0a, 0x41, 0x4b, 0x56, 0x54, -+ 0x71, 0x4f, 0x6b, 0x74, 0x35, 0x39, 0x2b, 0x63, 0x6f, 0x30, 0x4f, 0x33, 0x6d, 0x33, 0x68, 0x43, -+ 0x2b, 0x76, 0x35, 0x46, 0x62, 0x30, 0x30, 0x46, 0x6a, 0x59, 0x57, 0x63, 0x67, 0x65, 0x75, 0x33, -+ 0x45, 0x69, 0x6a, 0x4f, 0x55, 0x4c, 0x6f, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, -+ 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, -+ 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, -+ 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, -+ 0x49, 0x49, 0x43, 0x6a, 0x7a, 0x43, 0x43, 0x41, 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, -+ 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, -+ 0x37, 0x53, 0x56, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x43, -+ 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, -+ 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, -+ 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, -+ 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, -+ 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, -+ 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, -+ 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, -+ 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, -+ 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, -+ 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, -+ 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4d, 0x44, 0x55, 0x79, 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, -+ 0x55, 0x78, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, -+ 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, -+ 0x67, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, -+ 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, -+ 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, -+ 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, -+ 0x6d, 0x46, 0x30, 0x0a, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, -+ 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, -+ 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, -+ 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, -+ 0x42, 0x41, 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, -+ 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, -+ 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x43, 0x36, 0x6e, -+ 0x45, 0x77, 0x4d, 0x44, 0x49, 0x59, 0x5a, 0x4f, 0x6a, 0x2f, 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, -+ 0x61, 0x45, 0x4b, 0x69, 0x37, 0x0a, 0x31, 0x4f, 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, -+ 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, 0x4a, 0x66, 0x56, 0x6e, 0x6b, 0x59, 0x34, 0x75, 0x33, 0x49, -+ 0x6a, 0x6b, 0x44, 0x59, 0x59, 0x4c, 0x30, 0x4d, 0x78, 0x4f, 0x34, 0x6d, 0x71, 0x73, 0x79, 0x59, -+ 0x6a, 0x6c, 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, 0x46, 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, -+ 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, -+ 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, -+ 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, -+ 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, -+ 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x0a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, -+ 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, -+ 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, -+ 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, -+ 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x0a, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, -+ 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, -+ 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, -+ 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, -+ 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x0a, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, -+ 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, -+ 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, -+ 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x41, 0x66, -+ 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, -+ 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, -+ 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, 0x52, 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4e, -+ 0x6f, 0x6f, 0x77, 0x4c, 0x75, 0x50, 0x52, 0x4c, 0x73, 0x57, 0x47, 0x66, 0x2f, 0x59, 0x69, 0x37, -+ 0x47, 0x53, 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, 0x77, 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, -+ 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, 0x73, 0x2b, 0x58, 0x6f, 0x35, 0x6f, 0x2f, 0x73, -+ 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, 0x78, 0x48, 0x52, 0x41, 0x76, 0x5a, 0x55, 0x47, 0x4f, 0x64, -+ 0x52, 0x51, 0x37, 0x63, 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, -+ 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, -+ 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, 0x7b, 0x22, 0x65, 0x6e, 0x63, 0x6c, 0x61, 0x76, -+ 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x3a, 0x7b, 0x22, 0x69, 0x64, 0x22, -+ 0x3a, 0x22, 0x54, 0x44, 0x5f, 0x51, 0x45, 0x22, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, -+ 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x69, 0x73, 0x73, 0x75, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, -+ 0x3a, 0x22, 0x32, 0x30, 0x32, 0x34, 0x2d, 0x30, 0x39, 0x2d, 0x31, 0x38, 0x54, 0x30, 0x34, 0x3a, -+ 0x35, 0x34, 0x3a, 0x34, 0x31, 0x5a, 0x22, 0x2c, 0x22, 0x6e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, -+ 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x32, 0x34, 0x2d, 0x31, 0x30, 0x2d, 0x31, 0x38, -+ 0x54, 0x30, 0x34, 0x3a, 0x35, 0x34, 0x3a, 0x34, 0x31, 0x5a, 0x22, 0x2c, 0x22, 0x74, 0x63, 0x62, -+ 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4e, 0x75, -+ 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x31, 0x36, 0x2c, 0x22, 0x6d, 0x69, 0x73, 0x63, 0x73, 0x65, -+ 0x6c, 0x65, 0x63, 0x74, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, -+ 0x2c, 0x22, 0x6d, 0x69, 0x73, 0x63, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x61, 0x73, 0x6b, -+ 0x22, 0x3a, 0x22, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x22, 0x2c, 0x22, 0x61, 0x74, -+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x3a, 0x22, 0x31, 0x31, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x61, 0x74, -+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x22, 0x46, -+ 0x42, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x30, -+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, -+ 0x2c, 0x22, 0x6d, 0x72, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0x3a, 0x22, 0x44, 0x43, 0x39, -+ 0x45, 0x32, 0x41, 0x37, 0x43, 0x36, 0x46, 0x39, 0x34, 0x38, 0x46, 0x31, 0x37, 0x34, 0x37, 0x34, -+ 0x45, 0x33, 0x34, 0x41, 0x37, 0x46, 0x43, 0x34, 0x33, 0x45, 0x44, 0x30, 0x33, 0x30, 0x46, 0x37, -+ 0x43, 0x31, 0x35, 0x36, 0x33, 0x46, 0x31, 0x42, 0x41, 0x42, 0x44, 0x44, 0x46, 0x36, 0x33, 0x34, -+ 0x30, 0x43, 0x38, 0x32, 0x45, 0x30, 0x45, 0x35, 0x34, 0x41, 0x38, 0x43, 0x35, 0x22, 0x2c, 0x22, -+ 0x69, 0x73, 0x76, 0x70, 0x72, 0x6f, 0x64, 0x69, 0x64, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x74, 0x63, -+ 0x62, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x74, 0x63, 0x62, 0x22, -+ 0x3a, 0x7b, 0x22, 0x69, 0x73, 0x76, 0x73, 0x76, 0x6e, 0x22, 0x3a, 0x34, 0x7d, 0x2c, 0x22, 0x74, -+ 0x63, 0x62, 0x44, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x32, 0x33, 0x2d, 0x30, 0x38, -+ 0x2d, 0x30, 0x39, 0x54, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x5a, 0x22, 0x2c, 0x22, -+ 0x74, 0x63, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x55, 0x70, 0x54, 0x6f, -+ 0x44, 0x61, 0x74, 0x65, 0x22, 0x7d, 0x5d, 0x7d, 0x2c, 0x22, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, -+ 0x75, 0x72, 0x65, 0x22, 0x3a, 0x22, 0x39, 0x61, 0x35, 0x35, 0x34, 0x36, 0x35, 0x34, 0x38, 0x30, -+ 0x34, 0x36, 0x34, 0x61, 0x36, 0x66, 0x38, 0x64, 0x32, 0x33, 0x34, 0x62, 0x34, 0x32, 0x37, 0x65, -+ 0x39, 0x35, 0x30, 0x30, 0x30, 0x31, 0x39, 0x64, 0x66, 0x38, 0x39, 0x34, 0x37, 0x65, 0x65, 0x63, -+ 0x62, 0x35, 0x64, 0x62, 0x33, 0x37, 0x66, 0x61, 0x62, 0x35, 0x62, 0x62, 0x32, 0x37, 0x37, 0x32, -+ 0x38, 0x33, 0x38, 0x34, 0x64, 0x32, 0x62, 0x31, 0x62, 0x39, 0x62, 0x38, 0x63, 0x66, 0x37, 0x35, -+ 0x33, 0x39, 0x33, 0x32, 0x31, 0x34, 0x39, 0x33, 0x62, 0x65, 0x37, 0x31, 0x64, 0x61, 0x66, 0x34, -+ 0x61, 0x65, 0x39, 0x33, 0x32, 0x63, 0x61, 0x38, 0x30, 0x64, 0x37, 0x37, 0x64, 0x63, 0x36, 0x37, -+ 0x39, 0x34, 0x66, 0x34, 0x65, 0x66, 0x64, 0x31, 0x37, 0x34, 0x31, 0x30, 0x35, 0x61, 0x30, 0x37, -+ 0x32, 0x63, 0x35, 0x37, 0x61, 0x65, 0x22, 0x7d, 0x00, -+]; -+ -+//============================================================================== -+// Real servtd_get_quote implementation structures (from mikbras/tdtools) -+//============================================================================== -+ -+/// Global collateral storage for the servtd_get_quote function -+static COLLATERAL: Mutex> = Mutex::new(Vec::new()); -+ -+/// Ensure the collateral is initialized only once -+static INIT: Once = Once::new(); -+ -+/// Initialize the global collateral storage with hardcoded data -+fn init_collateral() { -+ INIT.call_once(|| { -+ let mut collateral = COLLATERAL.lock().unwrap(); -+ collateral.extend_from_slice(HARDCODED_COLLATERAL); -+ }); -+} -+ -+/// Quote header structure for servtd_get_quote -+#[repr(C)] -+pub struct QuoteHeader { -+ pub version: u64, -+ pub status: u64, -+ pub in_len: u32, -+ pub out_len: u32, -+ pub data: [u64; 0], // flexible array -+} -+ -+/// Message header structure -+#[repr(C)] -+pub struct MsgHeader { -+ pub major_version: u16, -+ pub minor_version: u16, -+ pub type_: u32, -+ pub size: u32, -+ pub error_code: u32, -+} -+ -+/// Get collateral response structure -+#[repr(C)] -+pub struct GetCollateralResponse { -+ pub header: MsgHeader, -+ pub major_version: u16, -+ pub minor_version: u16, -+ pub pck_crl_issuer_chain_size: u32, -+ pub root_ca_crl_size: u32, -+ pub pck_crl_size: u32, -+ pub tcb_info_issuer_chain_size: u32, -+ pub tcb_info_size: u32, -+ pub qe_identity_issuer_chain_size: u32, -+ pub qe_identity_size: u32, -+ pub collaterals: [u8; 0], // flexible array -+} -+ -+/// Packed collateral structure -+#[repr(C)] -+pub struct PackedCollateral { -+ pub major_version: u16, -+ pub minor_version: u16, -+ pub pck_crl_issuer_chain_size: u32, -+ pub root_ca_crl_size: u32, -+ pub pck_crl_size: u32, -+ pub tcb_info_issuer_chain_size: u32, -+ pub tcb_info_size: u32, -+ pub qe_identity_issuer_chain_size: u32, -+ pub qe_identity_size: u32, -+ pub data: [u8; 0], // flexible array -+} -+ -+/// Real implementation of servtd_get_quote (from mikbras/tdtools) -+#[no_mangle] -+pub unsafe extern "C" fn servtd_get_quote(blob: *mut QuoteHeader, _len: u64) -> i32 { -+ // Validate input parameters -+ if blob.is_null() { -+ return -1; -+ } -+ -+ // Initialize collateral if not already done -+ init_collateral(); -+ -+ let data = (*blob).data.as_ptr() as *mut u8; -+ if data.is_null() { -+ return -1; -+ } -+ -+ // Skip 4 bytes for message size -+ let rsp_ptr = data.add(4) as *mut GetCollateralResponse; -+ -+ let collateral = match COLLATERAL.lock() { -+ Ok(collateral) => collateral, -+ Err(_) => { -+ return -1; -+ } -+ }; -+ -+ if collateral.is_empty() { -+ return -1; -+ } -+ -+ // Validate that we have enough data for PackedCollateral structure -+ if collateral.len() < size_of::() { -+ return -1; -+ } -+ -+ // Read PackedCollateral from COLLATERAL -+ let pc_ptr = collateral.as_ptr() as *const PackedCollateral; -+ let pc = &*pc_ptr; -+ -+ (*rsp_ptr).major_version = pc.major_version; -+ (*rsp_ptr).minor_version = pc.minor_version; -+ (*rsp_ptr).pck_crl_issuer_chain_size = pc.pck_crl_issuer_chain_size; -+ (*rsp_ptr).root_ca_crl_size = pc.root_ca_crl_size; -+ (*rsp_ptr).pck_crl_size = pc.pck_crl_size; -+ (*rsp_ptr).tcb_info_issuer_chain_size = pc.tcb_info_issuer_chain_size; -+ (*rsp_ptr).tcb_info_size = pc.tcb_info_size; -+ (*rsp_ptr).qe_identity_issuer_chain_size = pc.qe_identity_issuer_chain_size; -+ (*rsp_ptr).qe_identity_size = pc.qe_identity_size; -+ -+ let collaterals = collateral.as_ptr().add(size_of::()); -+ let collaterals_size = collateral.len() - size_of::(); -+ -+ // Validate that the calculated message size won't overflow -+ let msg_size = size_of::().checked_add(collaterals_size); -+ let msg_size = match msg_size { -+ Some(size) => size, -+ None => return -1, // Overflow detected -+ }; -+ -+ ptr::copy_nonoverlapping( -+ collaterals, -+ (*rsp_ptr).collaterals.as_ptr() as *mut u8, -+ collaterals_size, -+ ); -+ -+ data.write(((msg_size >> 24) & 0xFF) as u8); -+ data.add(1).write(((msg_size >> 16) & 0xFF) as u8); -+ data.add(2).write(((msg_size >> 8) & 0xFF) as u8); -+ data.add(3).write((msg_size & 0xFF) as u8); -+ -+ (*rsp_ptr).header.major_version = 1; -+ (*rsp_ptr).header.minor_version = 0; -+ (*rsp_ptr).header.type_ = 3; -+ -+ let extra = 2 * size_of::(); -+ let total_size = msg_size.checked_add(extra); -+ let total_size = match total_size { -+ Some(size) => size, -+ None => return -1, // Overflow detected -+ }; -+ -+ (*rsp_ptr).header.size = total_size as u32; -+ (*rsp_ptr).header.error_code = 0; -+ -+ (*blob).status = 0; -+ let out_len = size_of::().checked_add(total_size); -+ let out_len = match out_len { -+ Some(len) => len, -+ None => return -1, // Overflow detected -+ }; -+ (*blob).out_len = out_len as u32; -+ -+ 0 -+} -diff --git a/src/attestation/src/ghci.rs b/src/attestation/src/ghci.rs -index 91c4ebe..623683b 100644 ---- a/src/attestation/src/ghci.rs -+++ b/src/attestation/src/ghci.rs -@@ -2,6 +2,9 @@ - // - // SPDX-License-Identifier: BSD-2-Clause-Patent - -+// This module is only compiled for non-AzCVMEmu modes -+#![cfg(not(feature = "AzCVMEmu"))] -+ - use core::ops::Range; - use core::sync::atomic::{AtomicU8, Ordering}; - use core::{ffi::c_void, slice::from_raw_parts_mut}; -diff --git a/src/attestation/src/lib.rs b/src/attestation/src/lib.rs -index 14fdab8..a216fe9 100644 ---- a/src/attestation/src/lib.rs -+++ b/src/attestation/src/lib.rs -@@ -2,13 +2,22 @@ - // - // SPDX-License-Identifier: BSD-2-Clause-Patent - --#![no_std] -+// Allow std for AzCVMEmu mode, otherwise use no_std -+#![cfg_attr(not(feature = "AzCVMEmu"), no_std)] - - extern crate alloc; - - mod attest; - mod binding; -+ -+// Conditionally compile ghci for non-AzCVMEmu modes -+#[cfg(not(feature = "AzCVMEmu"))] - mod ghci; -+ -+// Conditionally compile collateral for AzCVMEmu mode -+#[cfg(feature = "AzCVMEmu")] -+mod collateral; -+ - pub mod root_ca; - - pub use attest::*; -diff --git a/src/crypto/Cargo.toml b/src/crypto/Cargo.toml -index 04b05e2..65422ee 100644 ---- a/src/crypto/Cargo.toml -+++ b/src/crypto/Cargo.toml -@@ -18,3 +18,4 @@ zeroize = "1.5.7" - [features] - default = ["rustls_impl"] - rustls_impl = ["rustls", "ring"] -+AzCVMEmu = [] -diff --git a/src/crypto/src/rustls_impl/tls.rs b/src/crypto/src/rustls_impl/tls.rs -index a8b62ed..1255d18 100644 ---- a/src/crypto/src/rustls_impl/tls.rs -+++ b/src/crypto/src/rustls_impl/tls.rs -@@ -947,9 +947,17 @@ pub(crate) struct TlsTimeProvider; - - impl TimeProvider for TlsTimeProvider { - fn current_time(&self) -> Option { -- Some(UnixTime::since_unix_epoch(Duration::new( -- sys_time::get_sys_time()? as u64, -- 0, -- ))) -+ // Avoid RTC access in AzCVMEmu; use a fixed timestamp. -+ #[cfg(feature = "AzCVMEmu")] -+ { -+ Some(UnixTime::since_unix_epoch(Duration::new(1704067200u64, 0))) -+ } -+ #[cfg(not(feature = "AzCVMEmu"))] -+ { -+ Some(UnixTime::since_unix_epoch(Duration::new( -+ sys_time::get_sys_time()? as u64, -+ 0, -+ ))) -+ } - } - } -diff --git a/src/devices/vmcall_raw/Cargo.toml b/src/devices/vmcall_raw/Cargo.toml -index 6aff93e..74c37b2 100644 ---- a/src/devices/vmcall_raw/Cargo.toml -+++ b/src/devices/vmcall_raw/Cargo.toml -@@ -18,6 +18,11 @@ tdx-tdcall = { path = "../../../deps/td-shim/tdx-tdcall" } - td-payload = { path = "../../../deps/td-shim/td-payload", features = ["tdx"] } - td-shim-interface = { path = "../../../deps/td-shim/td-shim-interface", optional = true } - -+# AzCVMEmu optional deps (grouped) -+tdx-tdcall-emu = { path = "../../../deps/td-shim-AzCVMEmu/tdx-tdcall", optional = true } -+td-payload-emu = { path = "../../../deps/td-shim-AzCVMEmu/td-payload-emu", optional = true } -+ - [features] - vmcall-raw = ["td-shim-interface"] --fuzz = [] -\ No newline at end of file -+fuzz = [] -+AzCVMEmu = ["tdx-tdcall-emu", "td-payload-emu"] -diff --git a/src/devices/vmcall_raw/src/lib.rs b/src/devices/vmcall_raw/src/lib.rs -index 8a5fe4a..75ab0ce 100644 ---- a/src/devices/vmcall_raw/src/lib.rs -+++ b/src/devices/vmcall_raw/src/lib.rs -@@ -5,8 +5,20 @@ - #![cfg_attr(not(test), no_std)] - - extern crate alloc; -+ -+// For AzCVMEmu builds, alias td_payload_emu as td_payload so downstream modules can -+// keep using upstream-style `td_payload::...` imports without changes. -+#[cfg(feature = "AzCVMEmu")] -+extern crate td_payload_emu as td_payload; -+// No mutual exclusivity needed: real stack is the default, AzCVMEmu swaps to emu stack. - use core::fmt::{self, Display}; - use rust_std_stub::{error, io}; -+ -+// Conditional imports based on feature -+#[cfg(feature = "AzCVMEmu")] -+use tdx_tdcall_emu::TdVmcallError; -+ -+#[cfg(not(feature = "AzCVMEmu"))] - use tdx_tdcall::TdVmcallError; - - pub mod stream; -diff --git a/src/devices/vmcall_raw/src/transport/vmcall.rs b/src/devices/vmcall_raw/src/transport/vmcall.rs -index 6c273bc..d1326dd 100644 ---- a/src/devices/vmcall_raw/src/transport/vmcall.rs -+++ b/src/devices/vmcall_raw/src/transport/vmcall.rs -@@ -16,7 +16,10 @@ use lazy_static::lazy_static; - use spin::Mutex; - use td_payload::arch::idt::InterruptStack; - use td_payload::mm::shared::SharedMemory; -+#[cfg(not(feature = "AzCVMEmu"))] - use tdx_tdcall::tdx; -+#[cfg(feature = "AzCVMEmu")] -+use tdx_tdcall_emu::tdx; - - const MAX_VMCALL_RAW_STREAM_MTU: usize = 0x1000 * 16; - const VMCALL_VECTOR: u8 = 0x52; -diff --git a/src/migtd/Cargo.toml b/src/migtd/Cargo.toml -index 7023730..c247084 100644 ---- a/src/migtd/Cargo.toml -+++ b/src/migtd/Cargo.toml -@@ -43,6 +43,14 @@ x86 = "0.47.0" - x86_64 = { version = "0.14", default-features = false, features = ["instructions"] } - zerocopy = { version = "0.7", features = ["derive"] } - -+# AzCVMEmu optional deps (grouped) -+tdx-tdcall-emu = { path = "../../deps/td-shim-AzCVMEmu/tdx-tdcall", optional = true } -+td-payload-emu = { path = "../../deps/td-shim-AzCVMEmu/td-payload-emu", optional = true } -+td-shim-interface-emu = { path = "../../deps/td-shim-AzCVMEmu/td-shim-interface", optional = true, features = ["std"] } -+td-shim-emu = { path = "../../deps/td-shim-AzCVMEmu/td-shim", optional = true } -+env_logger = { version = "0.10.0", optional = true } -+tokio = { version = "1.0", features = ["rt", "rt-multi-thread"], optional = true } -+ - minicov = { version = "0.2", default-features = false, optional = true } - td-benchmark = { path = "../../deps/td-shim/devtools/td-benchmark", default-features = false, optional = true } - -@@ -59,4 +67,18 @@ vmcall-vsock = ["vsock/vmcall-vsock"] - vmcall-raw = ["vmcall_raw"] - test_heap_size = ["td-benchmark", "td-payload/test_heap_size"] - test_stack_size = ["td-benchmark"] --test_disable_ra_and_accept_all = ["attestation/test"] # Dangerous: can only be used for test purpose to bypass the remote attestation -+test_disable_ra_and_accept_all = ["attestation/test", "tdx-tdcall-emu?/test_disable_ra_and_accept_all"] # Dangerous: can only be used for test purpose to bypass the remote attestation -+AzCVMEmu = [ -+ "main", # Include main feature by default -+ "attestation/AzCVMEmu", -+ "crypto/AzCVMEmu", -+ "policy/AzCVMEmu", -+ "vmcall-raw", # Include vmcall-raw feature by default -+ "vmcall_raw/AzCVMEmu", -+ "td-shim-interface-emu", -+ "td-shim-emu", -+ "tdx-tdcall-emu", -+ "td-payload-emu", -+ "env_logger", -+ "tokio", -+] -diff --git a/src/migtd/build.rs b/src/migtd/build.rs -index 905609f..478e25a 100644 ---- a/src/migtd/build.rs -+++ b/src/migtd/build.rs -@@ -4,4 +4,11 @@ - - fn main() { - println!("cargo:rustc-link-arg=-defsym=__ImageBase=0"); -+ -+ // Only add attestation library linking for AzCVMEmu if not in test mode -+ #[cfg(all(feature = "AzCVMEmu", not(feature = "test_disable_ra_and_accept_all")))] -+ { -+ println!("cargo:rustc-link-arg=-lservtd_attest_app"); -+ println!("cargo:rustc-link-arg=-lcrypto"); -+ } - } -diff --git a/src/migtd/src/bin/migtd/cvmemu.rs b/src/migtd/src/bin/migtd/cvmemu.rs -new file mode 100644 -index 0000000..d4a10d0 ---- /dev/null -+++ b/src/migtd/src/bin/migtd/cvmemu.rs -@@ -0,0 +1,409 @@ -+// Copyright (c) 2022-2025 Intel Corporation -+// -+// SPDX-License-Identifier: BSD-2-Clause-Patent -+ -+//! AzCVMEmu-specific code for running MigTD in a standard Rust environment -+ -+#![cfg(feature = "AzCVMEmu")] -+ -+use std::env; -+use std::process; -+ -+use migtd; -+use migtd::migration::event; -+use migtd::migration::session::{exchange_msk, report_status}; -+use migtd::migration::{MigrationResult, MigtdMigrationInformation}; -+ -+use tdx_tdcall_emu::tdx_emu::{set_emulated_mig_request, EmuMigRequest}; -+use tdx_tdcall_emu::{init_tcp_emulation_with_mode, start_tcp_server_sync, TcpEmulationMode}; -+ -+// Import shared functions from main.rs -+use crate::{basic_info, do_measurements}; -+ -+// Helper to convert a MigrationResult by reference into its u8 code without moving it -+fn migration_result_code(e: &MigrationResult) -> u8 { -+ match e { -+ MigrationResult::Success => 0, -+ MigrationResult::InvalidParameter => 1, -+ MigrationResult::Unsupported => 2, -+ MigrationResult::OutOfResource => 3, -+ MigrationResult::TdxModuleError => 4, -+ MigrationResult::NetworkError => 5, -+ MigrationResult::SecureSessionError => 6, -+ MigrationResult::MutualAttestationError => 7, -+ MigrationResult::PolicyUnsatisfiedError => 8, -+ MigrationResult::InvalidPolicyError => 9, -+ } -+} -+ -+/// AzCVMEmu entry point - standard Rust main function -+pub fn main() { -+ // Initialize standard Rust logging for AzCVMEmu mode with info level by default -+ env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); -+ -+ // Init internal heap -+ #[cfg(not(feature = "test_disable_ra_and_accept_all"))] -+ attestation::attest_init_heap(); -+ -+ // Initialize event log emulation -+ td_shim_emu::event_log::init_event_log(); -+ // Parse command line arguments first so `-h` works without env vars/files -+ parse_commandline_args(); -+ // Initialize emulation layer (requires env vars/files); skipped if `-h` exited -+ initialize_emulation(); -+ -+ // Continue with the main runtime flow and exit with the returned code -+ let exit_code = runtime_main_emu(); -+ process::exit(exit_code); -+} -+ -+/// Initialize emulation layer -+fn initialize_emulation() { -+ // Get file paths from environment variables -+ let policy_file_path = match env::var("MIGTD_POLICY_FILE") { -+ Ok(path) => { -+ log::info!("MIGTD_POLICY_FILE set to: {}", path); -+ path -+ } -+ Err(_) => { -+ println!("MIGTD_POLICY_FILE environment variable not set"); -+ print_usage(); -+ process::exit(1); -+ } -+ }; -+ -+ let root_ca_file_path = match env::var("MIGTD_ROOT_CA_FILE") { -+ Ok(path) => { -+ log::info!("MIGTD_ROOT_CA_FILE set to: {}", path); -+ path -+ } -+ Err(_) => { -+ println!("MIGTD_ROOT_CA_FILE environment variable not set"); -+ print_usage(); -+ process::exit(1); -+ } -+ }; -+ -+ // Check if files exist before attempting to initialize -+ if !std::path::Path::new(&policy_file_path).exists() { -+ println!("Policy file not found: {}", policy_file_path); -+ print_usage(); -+ process::exit(1); -+ } -+ -+ if !std::path::Path::new(&root_ca_file_path).exists() { -+ println!("Root CA file not found: {}", root_ca_file_path); -+ print_usage(); -+ process::exit(1); -+ } -+ -+ // Initialize file-based emulation with real file access -+ // Convert strings to static references by leaking them (required by the API) -+ let policy_path: &'static str = Box::leak(policy_file_path.clone().into_boxed_str()); -+ let root_ca_path: &'static str = Box::leak(root_ca_file_path.clone().into_boxed_str()); -+ -+ let result = -+ td_shim_interface_emu::init_file_based_emulation_with_real_files(policy_path, root_ca_path); -+ -+ if result { -+ log::info!("File-based emulation initialized with real file access. Files will be loaded on demand from:"); -+ log::info!(" Policy: {}", policy_file_path); -+ log::info!(" Root CA: {}", root_ca_file_path); -+ } else { -+ log::error!("Failed to initialize file-based emulation"); -+ std::process::exit(1); -+ } -+} -+ -+/// Main runtime function for AzCVMEmu mode -+fn runtime_main_emu() -> i32 { -+ // Dump basic information of MigTD (reusing from main.rs) -+ basic_info(); -+ -+ // Perform measurements (reusing from main.rs) -+ do_measurements(); -+ -+ // Register callback -+ event::register_callback(); -+ -+ // Handle pre-migration for emulation mode and return exit code -+ handle_pre_mig_emu() -+} -+ -+fn parse_commandline_args() { -+ let args: Vec = env::args().collect(); -+ -+ // Default values -+ let mut mig_request_id = 1; -+ let mut is_source = true; -+ let mut target_td_uuid = [1, 2, 3, 4]; -+ let mut binding_handle = 0x1234; -+ let mut destination_ip: Option = None; -+ let mut destination_port: Option = None; -+ let mut help_requested = false; -+ -+ let mut i = 1; -+ while i < args.len() { -+ match args[i].as_str() { -+ "--request-id" | "-r" if i + 1 < args.len() => { -+ if let Ok(id) = args[i + 1].parse::() { -+ mig_request_id = id; -+ i += 2; -+ } else { -+ println!("Invalid request ID value: {}", args[i + 1]); -+ print_usage(); -+ process::exit(1); -+ } -+ } -+ "--role" | "-m" if i + 1 < args.len() => match args[i + 1].to_lowercase().as_str() { -+ "source" | "src" => { -+ is_source = true; -+ i += 2; -+ } -+ "destination" | "dst" | "target" => { -+ is_source = false; -+ i += 2; -+ } -+ _ => { -+ println!( -+ "Invalid role value: {}. Use 'source' or 'destination'", -+ args[i + 1] -+ ); -+ print_usage(); -+ process::exit(1); -+ } -+ }, -+ "--uuid" | "-u" if i + 4 < args.len() => { -+ if let (Ok(u1), Ok(u2), Ok(u3), Ok(u4)) = ( -+ args[i + 1].parse::(), -+ args[i + 2].parse::(), -+ args[i + 3].parse::(), -+ args[i + 4].parse::(), -+ ) { -+ target_td_uuid = [u1, u2, u3, u4]; -+ i += 5; -+ } else { -+ println!("Invalid UUID values. Expected 4 unsigned integers"); -+ print_usage(); -+ process::exit(1); -+ } -+ } -+ "--binding" | "-b" if i + 1 < args.len() => { -+ // Try to parse as hex (with 0x prefix) or decimal -+ let handle_result = -+ if args[i + 1].starts_with("0x") || args[i + 1].starts_with("0X") { -+ u64::from_str_radix(&args[i + 1][2..], 16) -+ } else { -+ args[i + 1].parse::() -+ }; -+ -+ if let Ok(handle) = handle_result { -+ binding_handle = handle; -+ i += 2; -+ } else { -+ println!("Invalid binding handle value: {}", args[i + 1]); -+ print_usage(); -+ process::exit(1); -+ } -+ } -+ "--dest-ip" | "-d" if i + 1 < args.len() => { -+ destination_ip = Some(args[i + 1].clone()); -+ i += 2; -+ } -+ "--dest-port" | "-t" if i + 1 < args.len() => { -+ if let Ok(port) = args[i + 1].parse::() { -+ destination_port = Some(port); -+ i += 2; -+ } else { -+ println!("Invalid destination port value: {}", args[i + 1]); -+ print_usage(); -+ process::exit(1); -+ } -+ } -+ "--help" | "-h" => { -+ help_requested = true; -+ i += 1; -+ } -+ _ => { -+ println!("Unknown argument: {}", args[i]); -+ help_requested = true; -+ i += 1; -+ } -+ } -+ } -+ -+ if help_requested { -+ print_usage(); -+ std::process::exit(0); -+ } -+ -+ // Create migration information using the same pattern as in data.rs -+ let mig_info = unsafe { -+ // Create a zero-initialized structure and then set the fields -+ let mut info: MigtdMigrationInformation = core::mem::zeroed(); -+ info.mig_request_id = mig_request_id; -+ info.migration_source = if is_source { 1 } else { 0 }; -+ info.target_td_uuid = [ -+ target_td_uuid[0] as u64, -+ target_td_uuid[1] as u64, -+ target_td_uuid[2] as u64, -+ target_td_uuid[3] as u64, -+ ]; -+ info.binding_handle = binding_handle; -+ info.mig_policy_id = 0; -+ info.communication_id = 0; -+ info -+ }; -+ -+ log::info!("Migration information:"); -+ log::info!(" Request ID: {}", mig_request_id); -+ log::info!( -+ " Role: {}", -+ if is_source { "Source" } else { "Destination" } -+ ); -+ log::info!(" Target TD UUID: {:?}", target_td_uuid); -+ log::info!(" Binding Handle: {:#x}", binding_handle); -+ -+ if let Some(ip) = &destination_ip { -+ log::info!(" Destination IP: {}", ip); -+ } -+ if let Some(port) = destination_port { -+ log::info!(" Destination Port: {}", port); -+ } -+ -+ // Determine IP and port (either from command line or use defaults) -+ let tcp_ip = destination_ip.as_deref().unwrap_or("127.0.0.1"); -+ let tcp_port = destination_port.unwrap_or(8001); -+ -+ // Configure TCP emulation mode -+ let mode = if is_source { -+ TcpEmulationMode::Client -+ } else { -+ TcpEmulationMode::Server -+ }; -+ -+ // Initialize TCP emulation -+ if let Err(e) = init_tcp_emulation_with_mode(tcp_ip, tcp_port, mode) { -+ log::error!("Failed to initialize TCP emulation: {}", e); -+ std::process::exit(1); -+ } -+ -+ // Handle connection logic based on role -+ if !is_source { -+ // Destination mode: start TCP server -+ let addr = format!("{}:{}", tcp_ip, tcp_port); -+ match start_tcp_server_sync(&addr) { -+ Ok(_) => { -+ log::info!("TCP server started successfully on: {}", addr); -+ } -+ Err(e) => { -+ log::error!("Failed to start TCP server: {:?}", e); -+ std::process::exit(1); -+ } -+ } -+ } else { -+ // Source mode: connect to destination server -+ let addr = format!("{}:{}", tcp_ip, tcp_port); -+ -+ // For source mode, establish the TCP client connection -+ use tdx_tdcall_emu::tdx_emu::connect_tcp_client; -+ match connect_tcp_client() { -+ Ok(_) => { -+ log::info!("Successfully connected to destination server at: {}", addr); -+ } -+ Err(e) => { -+ log::error!( -+ "Failed to connect to destination server at {}: {:?}", -+ addr, -+ e -+ ); -+ std::process::exit(1); -+ } -+ } -+ } -+ -+ // Seed waitforrequest emulation with the parsed MigrationInformation -+ set_emulated_mig_request(EmuMigRequest { -+ request_id: mig_info.mig_request_id, -+ migration_source: mig_info.migration_source as u8, -+ target_td_uuid: mig_info.target_td_uuid, -+ binding_handle: mig_info.binding_handle, -+ }); -+} -+ -+fn print_usage() { -+ println!("MigTD AzCVMEmu Mode Usage:"); -+ println!(); -+ println!("Required Environment Variables:"); -+ println!(" MIGTD_POLICY_FILE Path to the migration policy file"); -+ println!(" MIGTD_ROOT_CA_FILE Path to the root CA certificate file"); -+ println!(" Note: Accessing a vTPM (e.g., /dev/tpmrm0) may require sudo or proper device permissions."); -+ println!(" If using TPM2-TSS, you may need to export TSS2_TCTI=device:/dev/tpmrm0"); -+ println!(); -+ println!("Command Line Options:"); -+ println!(" --request-id, -r ID Set migration request ID (default: 1)"); -+ println!( -+ " --role, -m ROLE Set role as 'source' or 'destination' (default: source)" -+ ); -+ println!(" --uuid, -u U1 U2 U3 U4 Set target TD UUID as four integers (default: 1 2 3 4)"); -+ println!(" --binding, -b HANDLE Set binding handle as hex or decimal (default: 0x1234)"); -+ println!(" --dest-ip, -d IP Set destination IP address for connection (default: 127.0.0.1)"); -+ println!(" --dest-port, -t PORT Set destination port for connection (default: 8001)"); -+ println!(" --help, -h Show this help message"); -+ println!(); -+ println!("Examples:"); -+ println!(" export MIGTD_POLICY_FILE=config/policy.json"); -+ println!(" export MIGTD_ROOT_CA_FILE=config/Intel_SGX_Provisioning_Certification_RootCA.cer"); -+ println!(" ./migtd --role source --request-id 42"); -+ println!(" ./migtd -m destination -r 42 -b 0x5678"); -+ println!(" ./migtd --role source --dest-ip 192.168.1.100 --dest-port 8001"); -+} -+ -+fn handle_pre_mig_emu() -> i32 { -+ // For AzCVMEmu, create an async runtime and run the standard flow once -+ let rt = tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime"); -+ -+ // Run the standard sequence once for the single seeded request -+ let exit_code: i32 = rt.block_on(async move { -+ match migtd::migration::session::wait_for_request().await { -+ Ok(req) => { -+ // Call exchange_msk() and log its immediate outcome -+ let res = exchange_msk(&req).await; -+ match &res { -+ Ok(_) => log::info!("exchange_msk() returned Ok"), -+ Err(e) => log::error!( -+ "exchange_msk() returned error code {}", -+ migration_result_code(e) -+ ), -+ } -+ let status = res.map(|_| MigrationResult::Success).unwrap_or_else(|e| e); -+ -+ // Derive a numeric code without moving `status` -+ let status_code_u8 = status as u8; -+ -+ // Report status back via vmcall-raw emulation -+ if let Err(e) = report_status(status_code_u8, req.mig_info.mig_request_id).await { -+ log::error!("report_status failed with code {}", e as u8); -+ } else { -+ log::info!("report_status completed successfully"); -+ } -+ -+ if status_code_u8 == MigrationResult::Success as u8 { -+ log::info!("Migration key exchange successful!"); -+ 0 -+ } else { -+ let status_code = status_code_u8 as i32; -+ log::error!("Migration key exchange failed with code: {}", status_code); -+ status_code -+ } -+ } -+ Err(e) => { -+ let status_code = e as u8 as i32; -+ log::error!("wait_for_request failed with code: {}", status_code); -+ status_code -+ } -+ } -+ }); -+ -+ exit_code -+} -diff --git a/src/migtd/src/bin/migtd/main.rs b/src/migtd/src/bin/migtd/main.rs -index 6fe1f47..1934449 100644 ---- a/src/migtd/src/bin/migtd/main.rs -+++ b/src/migtd/src/bin/migtd/main.rs -@@ -2,8 +2,8 @@ - // - // SPDX-License-Identifier: BSD-2-Clause-Patent - --#![no_std] --#![no_main] -+#![cfg_attr(not(feature = "AzCVMEmu"), no_std)] -+#![cfg_attr(not(feature = "AzCVMEmu"), no_main)] - - extern crate alloc; - -@@ -18,6 +18,9 @@ use migtd::migration::MigrationResult; - use migtd::{config, event_log, migration}; - use spin::Mutex; - -+#[cfg(feature = "AzCVMEmu")] -+mod cvmemu; -+ - const MIGTD_VERSION: &str = env!("CARGO_PKG_VERSION"); - - // Event IDs that will be used to tag the event log -@@ -25,6 +28,7 @@ const TAGGED_EVENT_ID_POLICY: u32 = 0x1; - const TAGGED_EVENT_ID_ROOT_CA: u32 = 0x2; - const TAGGED_EVENT_ID_TEST: u32 = 0x32; - -+#[cfg(not(feature = "AzCVMEmu"))] - #[no_mangle] - pub extern "C" fn main() { - #[cfg(feature = "test_stack_size")] -@@ -34,6 +38,12 @@ pub extern "C" fn main() { - runtime_main() - } - -+// AzCVMEmu entry point - standard Rust main function -+#[cfg(feature = "AzCVMEmu")] -+fn main() { -+ cvmemu::main(); -+} -+ - pub fn runtime_main() { - let _ = td_logger::init(); - -@@ -57,11 +67,11 @@ pub fn runtime_main() { - handle_pre_mig(); - } - --fn basic_info() { -+pub fn basic_info() { - info!("MigTD Version - {}\n", MIGTD_VERSION); - } - --fn do_measurements() { -+pub fn do_measurements() { - // Get the event log recorded by firmware - let event_log = event_log::get_event_log_mut().expect("Failed to get the event log"); - -diff --git a/src/migtd/src/config.rs b/src/migtd/src/config.rs -index e30b82b..5052fec 100644 ---- a/src/migtd/src/config.rs -+++ b/src/migtd/src/config.rs -@@ -4,7 +4,11 @@ - - use r_efi::efi::Guid; - use td_layout::build_time::{TD_SHIM_CONFIG_BASE, TD_SHIM_CONFIG_SIZE}; -+ -+#[cfg(not(feature = "AzCVMEmu"))] - use td_shim_interface::td_uefi_pi::{fv, pi}; -+#[cfg(feature = "AzCVMEmu")] -+use td_shim_interface_emu::td_uefi_pi::{fv, pi}; - - pub const CONFIG_VOLUME_BASE: usize = TD_SHIM_CONFIG_BASE as usize; - pub const CONFIG_VOLUME_SIZE: usize = TD_SHIM_CONFIG_SIZE as usize; -diff --git a/src/migtd/src/event_log.rs b/src/migtd/src/event_log.rs -index e9bb734..2261bf5 100644 ---- a/src/migtd/src/event_log.rs -+++ b/src/migtd/src/event_log.rs -@@ -13,9 +13,16 @@ use cc_measurement::{ - use core::mem::size_of; - use crypto::hash::digest_sha384; - use spin::Once; -+#[cfg(not(feature = "AzCVMEmu"))] - use td_payload::acpi::get_acpi_tables; -+#[cfg(feature = "AzCVMEmu")] -+use td_shim_emu::event_log::{get_acpi_tables, MockCcel as Ccel}; -+#[cfg(not(feature = "AzCVMEmu"))] - use td_shim_interface::acpi::Ccel; -+#[cfg(not(feature = "AzCVMEmu"))] - use tdx_tdcall::tdx; -+#[cfg(feature = "AzCVMEmu")] -+use tdx_tdcall_emu::tdx; - use zerocopy::{AsBytes, FromBytes}; - - pub const EV_EVENT_TAG: u32 = 0x00000006; -diff --git a/src/migtd/src/lib.rs b/src/migtd/src/lib.rs -index f3a2218..d68145d 100644 ---- a/src/migtd/src/lib.rs -+++ b/src/migtd/src/lib.rs -@@ -2,8 +2,19 @@ - // - // SPDX-License-Identifier: BSD-2-Clause-Patent - --#![cfg_attr(not(test), no_std)] --#![cfg_attr(not(test), no_main)] -+#![cfg_attr(not(any(test, feature = "AzCVMEmu")), no_std)] -+#![cfg_attr(not(any(test, feature = "AzCVMEmu")), no_main)] -+ -+// AzCVMEmu only supports the vmcall-raw transport. -+#[cfg(all( -+ feature = "AzCVMEmu", -+ any( -+ feature = "virtio-serial", -+ feature = "vmcall-vsock", -+ feature = "virtio-vsock" -+ ) -+))] -+compile_error!("AzCVMEmu only supports vmcall-raw transport. Disable virtio-serial/vmcall-vsock/virtio-vsock when enabling AzCVMEmu."); - - #[cfg_attr(feature = "main", macro_use)] - extern crate alloc; -diff --git a/src/migtd/src/migration/event.rs b/src/migtd/src/migration/event.rs -index e0ee834..2c97cfc 100644 ---- a/src/migtd/src/migration/event.rs -+++ b/src/migtd/src/migration/event.rs -@@ -6,8 +6,15 @@ use alloc::collections::BTreeMap; - use core::sync::atomic::{AtomicBool, Ordering}; - use lazy_static::lazy_static; - use spin::Mutex; -+ -+#[cfg(not(feature = "AzCVMEmu"))] - use td_payload::arch::apic::*; -+#[cfg(not(feature = "AzCVMEmu"))] - use td_payload::arch::idt::{register_interrupt_callback, InterruptCallback, InterruptStack}; -+#[cfg(feature = "AzCVMEmu")] -+use td_payload_emu::arch::apic::*; -+#[cfg(feature = "AzCVMEmu")] -+use td_payload_emu::arch::idt::{register_interrupt_callback, InterruptCallback, InterruptStack}; - - pub const VMCALL_SERVICE_VECTOR: u8 = 0x50; - pub static VMCALL_SERVICE_FLAG: AtomicBool = AtomicBool::new(false); -diff --git a/src/migtd/src/migration/mod.rs b/src/migtd/src/migration/mod.rs -index 513190c..90aa530 100644 ---- a/src/migtd/src/migration/mod.rs -+++ b/src/migtd/src/migration/mod.rs -@@ -132,6 +132,7 @@ pub struct MigtdMigpolicy { - } - - #[repr(u8)] -+#[derive(Copy, Clone)] - pub enum MigrationResult { - Success = 0, - InvalidParameter = 1, -diff --git a/src/migtd/src/migration/session.rs b/src/migtd/src/migration/session.rs -index a6dc318..862b336 100644 ---- a/src/migtd/src/migration/session.rs -+++ b/src/migtd/src/migration/session.rs -@@ -2,6 +2,8 @@ - // - // SPDX-License-Identifier: BSD-2-Clause-Patent - -+#[cfg(not(feature = "AzCVMEmu"))] -+use crate::driver::ticks::with_timeout; - #[cfg(feature = "vmcall-raw")] - use crate::migration::event::VMCALL_MIG_REPORTSTATUS_FLAGS; - use alloc::collections::BTreeSet; -@@ -14,12 +16,22 @@ use core::{future::poll_fn, mem::size_of, task::Poll}; - use event::VMCALL_SERVICE_FLAG; - use lazy_static::lazy_static; - use spin::Mutex; -+#[cfg(not(feature = "AzCVMEmu"))] - use td_payload::mm::shared::SharedMemory; -+#[cfg(feature = "AzCVMEmu")] -+use td_payload_emu::mm::shared::SharedMemory; -+#[cfg(not(feature = "AzCVMEmu"))] - use tdx_tdcall::{ - td_call, - tdx::{self, tdcall_servtd_wr}, - TdcallArgs, - }; -+#[cfg(feature = "AzCVMEmu")] -+use tdx_tdcall_emu::{ -+ td_call, -+ tdx::{self, tdcall_servtd_wr}, -+ TdcallArgs, -+}; - use zerocopy::AsBytes; - - type Result = core::result::Result; -@@ -49,6 +61,18 @@ struct ExchangeInformation { - key: MigrationSessionKey, - } - -+// Local timeout helper: only for AzCVMEmu. Non-AzCVMEmu uses ticks::with_timeout. -+#[cfg(feature = "AzCVMEmu")] -+pub async fn with_timeout( -+ timeout: core::time::Duration, -+ fut: F, -+) -> core::result::Result { -+ match tokio::time::timeout(timeout, fut).await { -+ Ok(v) => Ok(v), -+ Err(_elapsed) => Err(crate::driver::ticks::TimeoutError), -+ } -+} -+ - impl Default for ExchangeInformation { - fn default() -> Self { - Self { -@@ -400,7 +424,6 @@ pub fn report_status(status: u8, request_id: u64) -> Result<()> { - - #[cfg(feature = "main")] - pub async fn exchange_msk(info: &MigrationInformation) -> Result<()> { -- use crate::driver::ticks::with_timeout; - use core::time::Duration; - - const TLS_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds -diff --git a/src/migtd/src/ratls/server_client.rs b/src/migtd/src/ratls/server_client.rs -index 87e41d1..dcda95b 100644 ---- a/src/migtd/src/ratls/server_client.rs -+++ b/src/migtd/src/ratls/server_client.rs -@@ -17,6 +17,8 @@ use crypto::{ - - use super::*; - use crate::event_log::get_event_log; -+#[cfg(feature = "AzCVMEmu")] -+use tdx_tdcall_emu as tdx_tdcall; - use verify::*; - - type Result = core::result::Result; -@@ -99,7 +101,6 @@ fn gen_quote(public_key: &[u8]) -> Result> { - let mut additional_data = [0u8; 64]; - additional_data[..hash.len()].copy_from_slice(hash.as_ref()); - let td_report = tdx_tdcall::tdreport::tdcall_report(&additional_data)?; -- - attestation::get_quote(td_report.as_bytes()).map_err(|_| RatlsError::GetQuote) - } - -@@ -186,6 +187,12 @@ mod verify { - } - - fn verify_public_key(verified_report: &[u8], public_key: &[u8]) -> CryptoResult<()> { -+ if cfg!(feature = "AzCVMEmu") { -+ // In AzCVMEmu mode, REPORTDATA is constructed differently. -+ // Bypass public key hash check in this development environment. -+ log::warn!("AzCVMEmu mode: Skipping public key verification in TD report. This is NOT secure for production use."); -+ return Ok(()); -+ } - const PUBLIC_KEY_HASH_SIZE: usize = 48; - - let report_data = &verified_report[520..520 + PUBLIC_KEY_HASH_SIZE]; -diff --git a/src/policy/Cargo.toml b/src/policy/Cargo.toml -index 10f75aa..75af831 100644 ---- a/src/policy/Cargo.toml -+++ b/src/policy/Cargo.toml -@@ -17,3 +17,4 @@ td-shim-interface = { path = "../../deps/td-shim/td-shim-interface"} - - [features] - std = [] -+AzCVMEmu = [] -diff --git a/src/policy/src/lib.rs b/src/policy/src/lib.rs -index c93771e..f47f3b3 100644 ---- a/src/policy/src/lib.rs -+++ b/src/policy/src/lib.rs -@@ -2,7 +2,7 @@ - // - // SPDX-License-Identifier: BSD-2-Clause-Patent - --#![no_std] -+#![cfg_attr(not(any(test, feature = "AzCVMEmu")), no_std)] - extern crate alloc; - - mod config; -diff --git a/src/policy/src/verify.rs b/src/policy/src/verify.rs -index c476709..b7dd9a1 100644 ---- a/src/policy/src/verify.rs -+++ b/src/policy/src/verify.rs -@@ -689,6 +689,13 @@ fn replay_event_log(event_log: &[u8], report_peer: &Report) -> Result<(), Policy - { - Ok(()) - } else { -+ //In AzCVMEmu mode, RTMR extension is emulated (no-op), RTMR in MigTD QUOTE won't match eventlog. -+ //Return OK in this development evnvironment. -+ #[cfg(feature = "AzCVMEmu")] -+ { -+ Ok(()) -+ } -+ #[cfg(not(feature = "AzCVMEmu"))] - Err(PolicyError::InvalidEventLog) - } - }